Skip to main content
This guide adds credential verification to your web app. Your verification program defines the accepted credentials and requested claims. AIR Kit handles credential discovery, the consent screen, and presentation generation. Your backend issues a nonce and verifies the returned SD-JWT presentation.

Before you start

You need:
  • An AIR Developer Dashboard account and Partner ID, with verifier functionality enabled
  • A web app with its origin registered in the Dashboard
  • A public HTTPS JWKS endpoint registered for your Partner ID
  • A server endpoint that signs short-lived Partner JWTs with scope: "verify"
  • A test holder with a matching credential from an issuer accepted by your program, or access to that issuer’s claim flow
  • A supported Node.js version for your web framework and AIR Kit
You do not need to operate an issuer backend or database to verify another issuer’s credentials. The issuance quickstart is optional. AIR login is required for this SDK flow; the code below includes it.

Step 1: Configure a verification program

  1. Open the Sandbox Developer Dashboard and copy your Partner ID from Account → General Settings.
  2. Under Verifier → Programs, create a program and select the accepted schema and issuer configuration.
  3. Select SD_JWT_VC as the accepted proof type and choose the claims to request.
  4. Publish or apply the program so it is active, and copy its verification program ID.
Predicate checks such as “age greater than 18” without revealing the value, and on-chain verification, need Iden3 credentials. See Iden3 credentials.

Step 2: Configure Partner authentication

The code below uses a Next.js app. Keep the private key on the server, including during local development.
Set your app’s environment variables:
Verification fails until AIR can fetch your JWKS. If you haven’t set one up for this Partner ID, follow JWKS endpoint. If you already issue credentials with the same Partner ID, reuse that JWKS and key pair. Create a server endpoint for verification tokens:
app/api/verification-token/route.ts
This example uses your Partner ID as the JWKS key’s kid. If your registered key uses a different kid, use that value in the token header.

Step 3: Initialize AIR Kit and start verification

Call this helper from a browser event handler, such as your Verify button:
lib/verify-credential.ts
The nonce needs at least 128 bits of randomness, as in the token route above. If your flow needs to redirect users to an issuer when they lack a credential, add the optional redirectUrl pointing to that issuer’s claim page. During verification, AIR Kit:
  1. Finds matching credentials. If none exist, the user needs to complete an accepted issuer’s issuance flow before verification can succeed.
  2. Fetches and decrypts the credential on the holder’s device.
  3. Shows the requested data and asks the user to consent.
  4. Records consent and generates the presentation. For a holder-bound credential, the holder signs a key-binding JWT over your nonce.
  5. Returns the outcome to your app.
Handle both returned statuses and errors, including a cancelled flow. Grant access only after a successful result appropriate to your application’s trust requirements.
The Compliant check runs in the browser, and the presentation wrapper is not signed. Your /api/verify-presentation route must verify the SD-JWT inside it: issuer signature, disclosures, expiry, credential type, and the key-binding JWT against your nonce and programId. Then it deletes the nonce. Follow Verify SD-JWT on your backend, which includes a reference implementation.

Step 5: Test the integration

Test with a matching credential, a credential that fails the requested condition, and a user who declines consent. Confirm your app handles missing credentials, expired tokens, and failed requests without granting access. Also confirm your backend rejects a replayed presentation (same nonce twice), a presentation made for another programId, and a presentation with a disclosure removed.

Troubleshooting

Next steps