You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Description: "Wallet resolves an offer URI, exchanges pre-authorized code for an access token, and requests an SD-JWT VC.",
183
+
Description: "Wallet resolves a credential offer URI, discovers issuer metadata, exchanges a pre-authorized code for an access token with c_nonce, and requests an SD-JWT VC bound to a proof JWT.",
184
184
Executable: true,
185
185
Category: "issuance",
186
186
Steps: []plugin.FlowStep{
187
187
{
188
188
Order: 1,
189
189
Name: "Resolve Credential Offer",
190
-
Description: "Wallet resolves credential_offer_uri and validates issuer metadata relationship.",
190
+
Description: "Wallet receives credential_offer_uri out-of-band and resolves it by fetching the credential offer object from the Credential Issuer (OID4VCI §4.1).",
191
191
From: "Wallet",
192
192
To: "Credential Issuer",
193
193
Type: "request",
194
194
Parameters: map[string]string{
195
-
"credential_offer_uri": "Reference URI returned out-of-band to the wallet",
195
+
"credential_offer_uri": "Reference URI delivered out-of-band to the wallet",
196
196
},
197
197
Security: []string{
198
-
"Credential offer envelope must include exactly one of credential_offer or credential_offer_uri",
198
+
"Credential offer envelope must include exactly one of credential_offer or credential_offer_uri (XOR)",
199
+
"Offer must contain credential_issuer, credential_configuration_ids, and grants with pre-authorized_code",
199
200
},
200
201
},
201
202
{
202
203
Order: 2,
203
-
Name: "Token Request (Pre-Authorized)",
204
-
Description: "Wallet uses the pre-authorized code to get a credential access token and c_nonce challenge.",
204
+
Name: "Discover Issuer Metadata",
205
+
Description: "Wallet fetches Credential Issuer Metadata from /.well-known/openid-credential-issuer to discover supported credential configurations, endpoints, and proof requirements (OID4VCI §5).",
"pre-authorized_code": "Code from credential offer grants block (REQUIRED)",
227
+
},
228
+
Security: []string{
229
+
"Content-Type must be application/x-www-form-urlencoded",
230
+
"Pre-authorized code is single-use and expires within offer TTL",
231
+
"If offer grant includes tx_code object, token request must include tx_code",
232
+
},
233
+
},
234
+
{
235
+
Order: 4,
236
+
Name: "Token Response",
237
+
Description: "Authorization Server validates the pre-authorized code and returns an access token with a c_nonce challenge for proof binding (OID4VCI §6.2).",
Description: "Credential Issuer validates proof key binding, nonce freshness, and audience, then returns the issued SD-JWT VC with a fresh c_nonce for subsequent requests (OID4VCI §7.3).",
237
276
From: "Credential Issuer",
238
277
To: "Wallet",
239
278
Type: "response",
279
+
Parameters: map[string]string{
280
+
"format": "dc+sd-jwt (SD-JWT VC serialization)",
281
+
"credential": "Issuer-signed JWT with selective disclosure segments",
282
+
"c_nonce": "Next challenge nonce for any follow-up credential requests",
283
+
"c_nonce_expires_in": "Next nonce lifetime in seconds",
284
+
},
285
+
Security: []string{
286
+
"Credential must be signed by the issuer using advertised key material and algorithm",
287
+
"SD-JWT includes _sd digests for selectively disclosable claims",
288
+
"Wallet stores issued credential material securely for later presentation",
289
+
},
240
290
},
241
291
},
242
292
},
243
293
{
244
294
ID: "oid4vci-pre-authorized-tx-code",
245
295
Name: "OID4VCI Pre-Authorized Code + tx_code",
246
-
Description: "Same as pre-authorized flow but with transaction code enforcement.",
296
+
Description: "Pre-authorized credential issuance with mandatory transaction code enforcement at token exchange — the offer's grant block declares a tx_code object requiring wallet to include a user-entered code (OID4VCI §6.1).",
247
297
Executable: true,
248
298
Category: "issuance",
249
299
Steps: []plugin.FlowStep{
250
300
{
251
301
Order: 1,
252
-
Name: "Resolve Offer with tx_code Constraint",
253
-
Description: "Offer declares a tx_code object requiring user-entered transaction code.",
302
+
Name: "Resolve Credential Offer with tx_code",
303
+
Description: "Wallet resolves credential_offer_uri and observes the tx_code object in the pre-authorized_code grant, indicating a transaction code is required at token exchange (OID4VCI §4.1.1).",
254
304
From: "Wallet",
255
305
To: "Credential Issuer",
256
306
Type: "request",
307
+
Parameters: map[string]string{
308
+
"credential_offer_uri": "Reference URI delivered out-of-band to the wallet",
309
+
},
310
+
Security: []string{
311
+
"Offer grant must include tx_code object with description, length, and input_mode",
312
+
"Wallet must prompt user for the transaction code before proceeding to token exchange",
313
+
},
257
314
},
258
315
{
259
316
Order: 2,
317
+
Name: "Discover Issuer Metadata",
318
+
Description: "Wallet fetches Credential Issuer Metadata to discover supported configurations, endpoints, and proof requirements (OID4VCI §5).",
"proof / proofs": "Proof object(s) with proof_type=jwt (REQUIRED)",
375
+
},
376
+
Security: []string{
377
+
"Proof JWT typ must be openid4vci-proof+jwt",
378
+
"Proof must bind to active c_nonce and credential issuer audience",
379
+
},
380
+
},
381
+
{
382
+
Order: 6,
383
+
Name: "Credential Response",
384
+
Description: "Credential Issuer validates proof and returns the issued SD-JWT VC with a fresh c_nonce (OID4VCI §7.3).",
385
+
From: "Credential Issuer",
386
+
To: "Wallet",
387
+
Type: "response",
388
+
Parameters: map[string]string{
389
+
"format": "dc+sd-jwt (SD-JWT VC serialization)",
390
+
"credential": "Issuer-signed JWT with selective disclosure segments",
391
+
"c_nonce": "Next challenge nonce",
392
+
},
393
+
Security: []string{
394
+
"Credential is signed by the issuer and returned as SD-JWT VC serialization",
395
+
},
273
396
},
274
397
},
275
398
},
276
399
{
277
400
ID: "oid4vci-deferred-issuance",
278
401
Name: "OID4VCI Deferred Credential Issuance",
279
-
Description: "Wallet receives transaction_id and polls deferred_credential endpoint until issuance is ready.",
402
+
Description: "Full pre-authorized code flow where the credential endpoint returns a transaction_id for deferred issuance — wallet polls the deferred_credential endpoint until the credential is ready (OID4VCI §9).",
280
403
Executable: true,
281
404
Category: "issuance",
282
405
Steps: []plugin.FlowStep{
283
406
{
284
407
Order: 1,
285
-
Name: "Initial Credential Request",
286
-
Description: "Issuer returns transaction_id instead of immediate credential.",
408
+
Name: "Resolve Credential Offer",
409
+
Description: "Wallet resolves credential_offer_uri from the Credential Issuer. The offer uses a pre-authorized_code grant and the issuer marks issuance for deferred delivery (OID4VCI §4.1).",
287
410
From: "Wallet",
288
411
To: "Credential Issuer",
289
412
Type: "request",
413
+
Parameters: map[string]string{
414
+
"credential_offer_uri": "Reference URI delivered out-of-band to the wallet",
415
+
},
416
+
Security: []string{
417
+
"Offer envelope must include exactly one of credential_offer or credential_offer_uri",
418
+
},
290
419
},
291
420
{
292
421
Order: 2,
293
-
Name: "Poll Deferred Endpoint",
294
-
Description: "Wallet polls deferred_credential endpoint using transaction_id.",
422
+
Name: "Discover Issuer Metadata",
423
+
Description: "Wallet fetches Credential Issuer Metadata to discover supported configurations, token endpoint, nonce endpoint, and deferred_credential_endpoint (OID4VCI §5).",
"proof / proofs": "Proof object(s) with proof_type=jwt (REQUIRED)",
475
+
},
476
+
Security: []string{
477
+
"Proof JWT typ must be openid4vci-proof+jwt",
478
+
"Proof must bind to active c_nonce and credential issuer audience",
479
+
},
480
+
},
481
+
{
482
+
Order: 6,
483
+
Name: "Deferred Credential Response",
484
+
Description: "Credential Issuer validates proof but responds with a transaction_id instead of an immediate credential, signalling deferred issuance (OID4VCI §9).",
303
485
From: "Credential Issuer",
304
486
To: "Wallet",
305
487
Type: "response",
488
+
Parameters: map[string]string{
489
+
"transaction_id": "Opaque identifier for the pending issuance transaction (REQUIRED)",
490
+
"c_nonce": "Next challenge nonce",
491
+
"c_nonce_expires_in": "Next nonce lifetime in seconds",
492
+
},
493
+
Security: []string{
494
+
"transaction_id is bound to the original access token — a different token cannot poll for this credential",
495
+
},
496
+
},
497
+
{
498
+
Order: 7,
499
+
Name: "Poll Deferred Endpoint",
500
+
Description: "Wallet polls the deferred_credential endpoint with transaction_id until the credential is ready. Issuer returns issuance_pending while processing (OID4VCI §9.1).",
501
+
From: "Wallet",
502
+
To: "Credential Issuer",
503
+
Type: "request",
504
+
Parameters: map[string]string{
505
+
"transaction_id": "Transaction ID from deferred credential response (REQUIRED)",
506
+
"Authorization": "Bearer {access_token} (REQUIRED — must match original token lineage)",
507
+
},
508
+
Security: []string{
509
+
"Access token must match the token used in the original credential request",
510
+
"Wallet should poll according to server guidance and apply reasonable backoff",
511
+
"issuance_pending error indicates credential is not yet ready",
512
+
},
513
+
},
514
+
{
515
+
Order: 8,
516
+
Name: "Credential Ready",
517
+
Description: "Credential Issuer returns the final SD-JWT VC once the issuance backend marks the transaction as ready (OID4VCI §9.1).",
518
+
From: "Credential Issuer",
519
+
To: "Wallet",
520
+
Type: "response",
521
+
Parameters: map[string]string{
522
+
"format": "dc+sd-jwt (SD-JWT VC serialization)",
523
+
"credential": "Issuer-signed JWT with selective disclosure segments",
524
+
},
525
+
Security: []string{
526
+
"Credential is identical to what would have been returned in an immediate response",
527
+
"Transaction is consumed — subsequent polls for the same transaction_id are rejected",
0 commit comments