@@ -40,6 +40,7 @@ import eu.europa.ec.eudi.wallet.internal.wrappedWithContentNegotiation
4040import eu.europa.ec.eudi.wallet.internal.wrappedWithLogging
4141import eu.europa.ec.eudi.wallet.issue.openid4vci.IssueEvent.Companion.failure
4242import eu.europa.ec.eudi.wallet.issue.openid4vci.OpenId4VciManager.Companion.TAG
43+ import eu.europa.ec.eudi.wallet.issue.openid4vci.dpop.DPopConfig
4344import eu.europa.ec.eudi.wallet.issue.openid4vci.reissue.ReissuanceConfig
4445import eu.europa.ec.eudi.wallet.issue.openid4vci.reissue.ReissuanceIssuer
4546import eu.europa.ec.eudi.wallet.logging.Logger
@@ -231,9 +232,18 @@ internal class DefaultOpenId4VciManager(
231232 launch(executor, onIssueResult) { coroutineScope, callback ->
232233 try {
233234
235+ // Resolve DPopConfig so DeferredContext can recreate the DPoP signer
236+ val resolvedDpopConfig = when (val cfg = config.dpopConfig) {
237+ DPopConfig .Disabled -> null
238+ DPopConfig .Default -> DPopConfig .Default .make(context)
239+ is DPopConfig .Custom -> cfg
240+ }
241+
234242 val deferredContext = DeferredContext .fromBytes(
235243 deferredDocument.relatedData,
236- walletAttestationKeyManager
244+ walletAttestationKeyManager,
245+ dpopConfig = resolvedDpopConfig,
246+ logger = logger,
237247 )
238248 val clientAttestationPopKeyId = deferredContext.clientAttestationPopKeyId
239249 when {
@@ -250,17 +260,20 @@ internal class DefaultOpenId4VciManager(
250260
251261 ProcessDeferredOutcome (
252262 documentManager = documentManager,
253- walletKeyManager = walletAttestationKeyManager,
254- clientAttestationPopKeyId = clientAttestationPopKeyId,
255263 callback = callback,
256264 deferredContext = ctx?.let {
257265 DeferredContext (
258266 issuanceContext = it,
259267 keyAliases = deferredContext.keyAliases,
260- clientAttestationPopKeyId = clientAttestationPopKeyId
268+ clientAttestationPopKeyId = clientAttestationPopKeyId,
269+ dPoPKeyAlias = deferredContext.dPoPKeyAlias,
270+ credentialConfigurationIdentifier = deferredContext.credentialConfigurationIdentifier,
271+ credentialEndpoint = deferredContext.credentialEndpoint,
272+ replacesDocumentId = deferredContext.replacesDocumentId,
261273 )
262274 } ? : deferredContext,
263- logger = logger
275+ logger = logger,
276+ reissuanceStorage = reissuanceStorage,
264277 ).process(deferredDocument, deferredContext.keyAliases, outcome)
265278 }
266279 }
@@ -354,33 +367,34 @@ internal class DefaultOpenId4VciManager(
354367
355368 // Process the response: store new document, then delete old one
356369 val issuedDocumentIds = mutableListOf<DocumentId >()
370+ val deferredDocumentIds = mutableListOf<DocumentId >()
357371 ProcessResponse (
358372 documentManager = documentManager,
359- deferredContextFactory = DeferredContextFactory (issuer, authorizedRequest),
360- walletKeyManager = walletAttestationKeyManager,
373+ deferredContextFactory = DeferredContextFactory (issuer, authorizedRequest, issuerCreator.dpopKeyAlias),
361374 clientAttestationPopKeyId = issuerCreator.clientAttestationPopKeyId,
362375 listener = listener,
363376 issuedDocumentIds = issuedDocumentIds,
377+ deferredDocumentIds = deferredDocumentIds,
364378 logger = logger,
365379 authorizedRequest = authorizedRequest,
366380 issuer = issuer,
367381 documentToConfigurationMap = requestMap,
368382 dpopKeyAlias = issuerCreator.dpopKeyAlias,
369383 reissuanceStorage = reissuanceStorage,
370384 clientAuthentication = issuerCreator.clientAuthentication,
385+ replacesDocumentId = documentId,
371386 ).process(response)
372387
373- // If new document(s) issued successfully, delete the old document
374- // and migrate the re-issuance metadata
388+ // If new document(s) issued successfully, delete the old document.
389+ // If the outcome was deferred, the old document stays alive — the
390+ // replacesDocumentId stored in the deferred context will trigger
391+ // deletion when issueDeferredDocument() eventually succeeds.
375392 if (issuedDocumentIds.isNotEmpty()) {
376- // Delete the old document — the DocumentManagerWithReissuance wrapper
377- // automatically cleans up re-issuance metadata for the old document.
378- // New metadata was already stored by ProcessResponse.storeReissuanceMetadata.
379393 documentManager.deleteDocumentById(documentId)
380394 logger?.d(TAG , " Deleted old document $documentId after re-issuance" )
381395 }
382396
383- listener(IssueEvent .Finished (issuedDocumentIds))
397+ listener(IssueEvent .Finished (issuedDocumentIds + deferredDocumentIds ))
384398
385399 } catch (e: Throwable ) {
386400 logger?.e(TAG , " Something went wrong with reissuance of $documentId " , e)
@@ -440,6 +454,7 @@ internal class DefaultOpenId4VciManager(
440454 var authorizedRequest = issuerAuthorization.authorize(issuer, txCode)
441455 listener(IssueEvent .Started (offer.offeredDocuments.size))
442456 val issuedDocumentIds = mutableListOf<DocumentId >()
457+ val deferredDocumentIds = mutableListOf<DocumentId >()
443458 val documentCreator = DocumentCreator (
444459 documentManager = documentManager,
445460 listener = listener,
@@ -453,11 +468,11 @@ internal class DefaultOpenId4VciManager(
453468 }
454469 ProcessResponse (
455470 documentManager = documentManager,
456- deferredContextFactory = DeferredContextFactory (issuer, authorizedRequest),
457- walletKeyManager = walletAttestationKeyManager,
471+ deferredContextFactory = DeferredContextFactory (issuer, authorizedRequest, issuerCreator.dpopKeyAlias),
458472 clientAttestationPopKeyId = issuerCreator.clientAttestationPopKeyId,
459473 listener = listener,
460474 issuedDocumentIds = issuedDocumentIds,
475+ deferredDocumentIds = deferredDocumentIds,
461476 logger = logger,
462477 authorizedRequest = authorizedRequest,
463478 issuer = issuer,
@@ -466,7 +481,7 @@ internal class DefaultOpenId4VciManager(
466481 reissuanceStorage = reissuanceStorage,
467482 clientAuthentication = issuerCreator.clientAuthentication,
468483 ).process(response)
469- listener(IssueEvent .Finished (issuedDocumentIds))
484+ listener(IssueEvent .Finished (issuedDocumentIds + deferredDocumentIds ))
470485 }
471486
472487 /* *
0 commit comments