HomeOpenID4VCIIssuance Flows

Issuance Flows

Detailed walkthrough of the Authorization Code and Pre-Authorized Code flows, including deferred issuance for asynchronous credential generation.

Authorization Code Flow

The standard OAuth 2.0 Authorization Code flow extended for credential issuance. The user authenticates at the issuer and consents to credential issuance.

1 Discovery

Wallet fetches issuer metadata from /.well-known/openid-credential-issuer to learn about supported credentials, endpoints, and capabilities.

2 Authorization Request

Wallet redirects user to Authorization Server with requested credential type (via scope or authorization_details).

GET /authorize?
  response_type=code
  &client_id=wallet123
  &redirect_uri=https://wallet.example/callback
  &scope=openid UniversityDegreeCredential
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256

3 Token Request

Wallet exchanges authorization code for access token. Response includes c_nonce for proof of possession.

POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://wallet.example/callback
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

4 Credential Request

Wallet creates proof of possession with c_nonce and requests credential.

POST /credential
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...
Content-Type: application/json

{
  "credential_configuration_id": "UniversityDegreeCredential",
  "proof": {
    "proof_type": "jwt",
    "jwt": "eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIs..."
  }
}

Pre-Authorized Code Flow

When the issuer has already verified the user (e.g., in-person at a DMV, via existing account), they can issue a pre-authorized code that the wallet exchanges directly for a token.

Skips Authorization Endpoint
The pre-authorized code goes directly to the token endpoint. No user interaction at the authorization server is needed.

Token Request with Pre-Authorized Code

POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code
&pre-authorized_code=SplxlOBeZQQYbYS6WxSbIA
&tx_code=493536

Transaction Code (tx_code)

An optional PIN or code sent via separate channel (SMS, email) to bind the pre-authorized code to the legitimate user. Prevents interception attacks.

input_mode

"numeric" or "text"

length

Expected code length (e.g., 6)

Deferred Issuance

When credential generation takes time (e.g., requires human review), the issuer returns a transaction_id instead of the credential. The wallet polls the deferred endpoint until the credential is ready.

Initial Response (Deferred)

HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "transaction_id": "8xLOxBtZp8",
  "c_nonce": "wlbQc6pCJp",
  "c_nonce_expires_in": 86400,
  "interval": 5
}

Polling the Deferred Endpoint

POST /deferred
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Content-Type: application/json

{
  "transaction_id": "8xLOxBtZp8"
}

When to Use Which Flow

ScenarioRecommended Flow
User discovers credential in wallet appAuthorization Code
Issuer already verified user (DMV visit)Pre-Authorized Code
QR code at physical locationPre-Authorized Code
Email with credential claim linkPre-Authorized Code
Real-time identity verification neededAuthorization Code
Manual review of applicationEither + Deferred