Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.moca.network/llms.txt

Use this file to discover all available pages before exploring further.

BLOCKING — Partner JWKS endpoint required. issueCredential, verifyCredential, and Issue on Behalf all fail until you (1) host a public HTTPS JWKS URL, (2) register it in Dashboard → Account → General → JWKS URL, and (3) sign your Partner JWT with a kid that matches a key in that JWKS. Localhost is not reachable from AIR servers — use an HTTPS tunnel (ngrok, cloudflared) or deploy. See JWKS endpoint setup.
You need to generate and use the JWT when:
  • Authenticating a User
  • Performing credentials-related operations such as issuing or verifying credentials
For Issue on Behalf (server-side credential issuance without user presence), the JWT must include scope: "issue on-behalf", typ: "JWT", and the target user’s email claim. See Issue on Behalf for concepts and Issue on Behalf API & Examples for endpoint usage. JWT Details
  • Signing algorithms supported: ES256, RS256
  • Expiry: 5 min (recommended)
  • Claims: varies depending on the operation. You would always need to include your partnerId as one of the claims
  • Header: You must include a kid (Key ID) header to indicate which key was used to sign the JWT. AIR Kit uses kid to select the matching key from your JWKS endpoint.
  • JWKS URL: AIR Kit validates your JWT using JWK standards (RFC 7517). You must publish your public key at a JWKS URL and register it in the dashboard. See JWKS endpoint setup for the full procedure.
To learn more about JWT, visit jwt.io.

JWKS endpoint (required for all credential SDK operations)

issueCredential, verifyCredential, and Issue on Behalf all rely on the same Partner JWT trust model — AIR Kit fetches your registered JWKS URL and validates every JWT against it. The endpoint must be:
  • A public HTTPS URL reachable from AIR servers (localhost is not enough).
  • Registered in Dashboard → Account → General Settings → JWKS URL as the full URL your app actually serves.
  • Returning a JSON document whose keys[].kid matches the kid you set in your JWT header.
The canonical Next.js route is app/api/.well-known/jwks/route.ts, used by every issuer and verifier in air-examples. For implementation, dashboard registration, local HTTPS tunnels, and the kid rule, see the JWKS endpoint setup page.

Issue-on-Behalf JWT specifics

For Issue on Behalf (API), use a Partner JWT with these fields:
CategoryRequired fieldsNotes
ClaimspartnerId, scope: "issue on-behalf", emailemail must be the target user’s AIR Account email
Headerkid, typ: "JWT"kid identifies which key in your JWKS is used
AlgorithmRS256 or ES256Keep consistent with your JWKS key type
Expiryexp (recommended 5 minutes)Short-lived token recommended
JWKS rules (endpoint reachability, registration, kid matching) apply identically to Issue on Behalf — there is no separate JWKS configuration for the on-behalf flow. Focused Node.js example (payload + header shape):
const jwt = require("jsonwebtoken");
const fs = require("fs");

const privateKey = fs.readFileSync("path/to/private.key");
const now = Math.floor(Date.now() / 1000);

const payload = {
  partnerId: "your-partner-id",
  scope: "issue on-behalf",
  email: "user@example.com",
  iat: now,
  exp: now + 5 * 60
};

const token = jwt.sign(payload, privateKey, {
  algorithm: "RS256",
  header: {
    kid: "your-partner-id",
    typ: "JWT"
  }
});

Generating Partner JWTs

Generating an RS256 Key Pair

To generate a private/public key pair, you may use OpenSSL:
# Generate a 2048-bit RSA private key
openssl genpkey -algorithm RSA -out private.key -pkeyopt rsa_keygen_bits:2048

# Extract the public key in PEM format
openssl rsa -pubout -in private.key -out public.key
  • private.key: Use this file as your signing key in backend code.
  • public.key: Use this to configure your JWKS endpoint for JWT verification.
Tip: Keep your private key secure and never share it publicly.

Examples

Below are backend code examples for generating a JWT using ES256 or RS256 algorithms, including the kid (Key ID) header.
const jwt = require("jsonwebtoken");
const fs = require("fs");

const privateKey = fs.readFileSync("path/to/private.key");
const payload = {
  partnerId: "your-partner-id",
  // other claims as needed
  exp: Math.floor(Date.now() / 1000) + 5 * 60 // 5 minutes expiry
};

const token = jwt.sign(payload, privateKey, {
  algorithm: "RS256",
  header: {
    kid: "your-key-id"
  }
});
console.log(token);