Skip to content

Conversation

hacdias
Copy link
Contributor

@hacdias hacdias commented Aug 7, 2025

This PR adds support fopr deferred credential issuance within the OpenID4VCI specification. Some notes:

There are still a few small questions left to answer:

  1. Are deferred and partial issuance compatible with each other? I assumed that no, since the specification was not clear enough for me. However, if they are compatible, I need to update the code to allow multiple transaction IDs per issuance session.
  2. I'm not sure if we need to change something in the token creation logic. Do we need to make them live longer?
  3. I did not change anything in the validity of an issuance session. On the deferred credential issuance endpoint, I just do not check for the expiration time, since it's no longer relevant. Is there any cleanup of the issuance session repository? Do I need to make sure it does not get deletedr in some way?

Copy link

changeset-bot bot commented Aug 7, 2025

🦋 Changeset detected

Latest commit: 241cb57

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@credo-ts/openid4vc Minor
@credo-ts/action-menu Minor
@credo-ts/anoncreds Minor
@credo-ts/askar Minor
@credo-ts/cheqd Minor
@credo-ts/core Minor
@credo-ts/didcomm Minor
@credo-ts/drpc Minor
@credo-ts/indy-sdk-to-askar-migration Minor
@credo-ts/indy-vdr Minor
@credo-ts/node Minor
@credo-ts/question-answer Minor
@credo-ts/react-native Minor
@credo-ts/redis-cache Minor
@credo-ts/tenants Minor
@credo-ts/webvh Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch 2 times, most recently from 4c605d4 to 15a5399 Compare August 11, 2025 07:58
@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch 3 times, most recently from 8898837 to c29cb03 Compare August 11, 2025 09:55
@hacdias
Copy link
Contributor Author

hacdias commented Aug 11, 2025

@TimoGlastra I'm opening this for review. Please note that there are still some open questions that I was hoping getting some feedback on: #2350 (comment)

@hacdias hacdias marked this pull request as ready for review August 11, 2025 09:56
@hacdias hacdias requested a review from a team as a code owner August 11, 2025 09:56
@hacdias hacdias requested a review from TimoGlastra August 11, 2025 12:47
@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch from c29cb03 to e90c3ff Compare August 11, 2025 13:12
@TimoGlastra
Copy link
Contributor

Are deferred and partial issuance compatible with each other? I assumed that no, since the specification was not clear enough for me. However, if they are compatible, I need to update the code to allow multiple transaction IDs per issuance session.

Partial issuance is something we added in Credo. It's if you offer multiple configurations in a offer, and only a subset of those have been issued. Every issuance flow that offers multiple credentials will reach this state, so yes I'd say we have to make them compatible with each other.

I'm not sure if we need to change something in the token creation logic. Do we need to make them live longer?

This is a good question. We could make them live longer, but i think we should also consider to add support for refresh tokens. (this will enable credential refresh, something we want to support as well). Using a refresh token you can get a new access token.

Some considerations to this:

  • We should add the option to issue a refresh token that is also bound to the pre-authorized_code or issuer_state and has the same sub.
  • For deferred issuance we should probably require refresh tokens
  • We should allow exchanging a refresh token (with same DPoP and Client Attestation) for an access token

I did not change anything in the validity of an issuance session. On the deferred credential issuance endpoint, I just do not check for the expiration time, since it's no longer relevant. Is there any cleanup of the issuance session repository? Do I need to make sure it does not get deletedr in some way?

We use it in e.g. Paradym to remove expired sessions. So i think we should update this as well. But we probably want to have longer expiration for the deferred issuance than the issuance session as a whole 🤔

@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch 2 times, most recently from ea52111 to ca620f4 Compare August 11, 2025 13:53
@TimoGlastra
Copy link
Contributor

Also mainly a question on the overall flow. If you want to use deferred issuance in credo you should:

  • implement the mapper to return deferred credential (an interval)
  • store the keys/attestation associated with the request outside of credo for processing, along with a transaction id
  • Implement the deferred mapper to return the credential at a later stage?

@hacdias
Copy link
Contributor Author

hacdias commented Aug 11, 2025

implement the mapper to return deferred credential (an interval)

Yes, and transaction id. I considered generating the transaction id in Credo itself, but that'd make it more complicated, since we'd need to "give" that information back to the implementer.

store the keys/attestation associated with the request outside of credo for processing, along with a transaction id

Yes.

Implement the deferred mapper to return the credential at a later stage?

Yes

@TimoGlastra
Copy link
Contributor

I considered generating the transaction id in Credo itself, but that'd make it more complicated, since we'd need to "give" that information back to the implementer.

Makes sense, users just need to be careful to genreate unique transaction ids since it can cause issues if they clash

@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch 2 times, most recently from 90b8a0b to dbf356a Compare August 12, 2025 07:48
@hacdias
Copy link
Contributor Author

hacdias commented Aug 12, 2025

We use it in e.g. Paradym to remove expired sessions. So i think we should update this as well. But we probably want to have longer expiration for the deferred issuance than the issuance session as a whole 🤔

At the moment, issuanceSession does not really have an "expiry date". We just use createdAt with statefulCredentialOfferExpirationInSeconds.

Update: I introduced a expiresAt variable, which is initially set to createdAt + statefulCredentialOfferExpirationInSeconds (preserving current behavior). Every time it gets deferred, we change expiresAt to be the maximum between:

  1. Current expiresAt
  2. Current time + interval * 2
  3. Current time + statefulCredentialOfferExpirationInSeconds

This accounts for multiple deferred credentials with potentially longer intervals, hence we keep checking what's currently set as expiry time. 3 is just a measure to not allow it to be too short, and allow time for the wallet to get a new token and fetch the creedentials.

@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch 3 times, most recently from d1e773a to fb6db25 Compare August 12, 2025 08:22
@hacdias
Copy link
Contributor Author

hacdias commented Aug 12, 2025

but i think we should also consider to add support for refresh tokens. (this will enable credential refresh, something we want to support as well). Using a refresh token you can get a new access token.

I will work on adding support for refresh tokens on https://github.com/openwallet-foundation-labs/oid4vc-ts

@TimoGlastra
Copy link
Contributor

but i think we should also consider to add support for refresh tokens. (this will enable credential refresh, something we want to support as well). Using a refresh token you can get a new access token.

I will work on adding support for refresh tokens on https://github.com/openwallet-foundation-labs/oid4vc-ts

We can also add it in another PR, since we won't have to change the logic for deferred issuance for it

@hacdias
Copy link
Contributor Author

hacdias commented Aug 12, 2025

@TimoGlastra yes, let's merge this one first.

I will work on the refresh tokens in. a separate PR.

@hacdias hacdias requested a review from TimoGlastra August 12, 2025 11:14
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Henrique Dias <mail@hacdias.com>
@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch from bfbf411 to fabad07 Compare August 12, 2025 11:36
@hacdias
Copy link
Contributor Author

hacdias commented Aug 12, 2025

@TimoGlastra just rebased with latest updates from main :)

Signed-off-by: Henrique Dias <mail@hacdias.com>
@hacdias hacdias force-pushed the feat/deferred-credential-issuance branch from fabad07 to 241cb57 Compare August 12, 2025 11:38
@TimoGlastra TimoGlastra merged commit cfc2ac4 into openwallet-foundation:main Aug 12, 2025
12 of 13 checks passed
@hacdias hacdias deleted the feat/deferred-credential-issuance branch August 12, 2025 12:04
@Sshovon
Copy link
Contributor

Sshovon commented Aug 12, 2025

Hey @hacdias , I ran into a couple of runtime errors while testing credential retrieval from an offer. Initially I got,

TypeError: expiresAt.getTime is not a function.

After converting expiresAt to a Date with new Date(expiresAt).getTime(), the next error appeared:

TypeError: options.preAuthorizedCodeExpiresAt.getTime is not a function

It looks like in some code paths these fields are strings rather than Date instances.
I think these issues are connected with this PR. Please ignore if they are not. Thanks.

@hacdias
Copy link
Contributor Author

hacdias commented Aug 13, 2025

@Sshovon thanks, I think this should fix it: #2357

genaris pushed a commit to genaris/credo-ts that referenced this pull request Oct 9, 2025
Signed-off-by: Henrique Dias <mail@hacdias.com>
Signed-off-by: Ariel Gentile <gentilester@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants