Before you start
You need:- An AIR Developer Dashboard account and Partner ID, with verifier functionality enabled
- A web app served over HTTPS, with its origin whitelisted under Account → Domains
- 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
Step 1: Configure a verification program
- Open the Sandbox Developer Dashboard and copy your Partner ID from Account → General Settings.
- Under Verifier → Programs, create a program and select the accepted schema and issuer configuration.
- Select
SD_JWT_VCas the accepted proof type and choose the claims to request. - Publish or apply the program so it is active, and copy its verification program ID.
Step 2: Configure Partner authentication
The code below uses a Next.js app. Keep the private key on the server, including during local development.Authorization: Bearer <token>, and the backend validates it
against AIR’s JWKS (see Sessions).
This file does that, and stores one pending nonce per user:
lib/air-session.ts
app/api/verification-token/route.ts
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
redirectUrl pointing to that issuer’s claim page.
Step 4: Obtain consent and handle the result
During verification, AIR Kit:- Finds matching credentials. If none exist, the user needs to complete an accepted issuer’s issuance flow before verification can succeed.
- Fetches and decrypts the credential on the holder’s device.
- Shows the requested data and asks the user to consent.
- Records consent and generates the presentation. Because you passed a
nonce, the holder signs a key-binding JWT with their private signing key.
It covers the credential, the disclosed claims, nonce, and
programId, so a leaked presentation cannot be replayed. - Returns the outcome to your app.
Step 5: Verify the presentation on your backend
TheCompliant check runs in the browser, and the presentation wrapper is not
signed. Your backend verifies the SD-JWT inside it: issuer signature,
disclosures, expiry, credential type, and the key-binding JWT against the
user’s nonce and your programId.
Verify SD-JWT on your backend as
lib/verify-air-sd-jwt.ts, then create the route:
app/api/verify-presentation/route.ts
Step 6: Test the integration
Run the test through your HTTPS tunnel URL, with the tunnel domain whitelisted under Account → Domains and the tunnel’s JWKS URL registered. 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 (a second submit gets400 No pending verification), a presentation made for another programId, and
a presentation with a disclosure removed.
Troubleshooting
Next steps
- Verification reference
- Verify SD-JWT on your backend
- Architecture and data flow
- Credential issuance quickstart, if you also operate an issuer