Skip to content

[OID4VCI] Fix unbounded OID4VCI credential offer expiration#50957

Open
forkimenjeckayang wants to merge 3 commits into
keycloak:mainfrom
adorsys:issue-50520
Open

[OID4VCI] Fix unbounded OID4VCI credential offer expiration#50957
forkimenjeckayang wants to merge 3 commits into
keycloak:mainfrom
adorsys:issue-50520

Conversation

@forkimenjeckayang

Copy link
Copy Markdown
Contributor

This change prevents /create-credential-offer from creating credential
offers and pre-authorized codes with an unbounded expiration.

It also binds REST-created pre-authorized offers to the session that
authorized their creation, allowing logout and password changes to revoke
outstanding pre-authorized codes.

Changes

  • Validate the expire parameter:
    • It must be later than the current time.
    • It must not exceed the configured credential-offer lifespan.
  • Use long expiration timestamps to avoid integer overflow.
  • Record the creation time of credential offers.
  • Reject offers whose lifetime exceeds the configured maximum.
  • Reject legacy pre-authorized offers without creation-time information.
  • Store the originating user and user-session identifiers for REST-created
    pre-authorized offers.
  • Record the originating user's password credential creation timestamp.
  • Reject pre-authorized code redemption when:
    • The originating session no longer exists or is no longer active.
    • The originating user is disabled or no longer matches the session.
    • The originating user's password has changed.
  • Keep the originating session active in wallet tests until the
    pre-authorized code is redeemed.
  • Preserve compatibility with existing CredentialOfferProvider
    implementations through the existing Integer-based SPI method.

closes #50520

@forkimenjeckayang
forkimenjeckayang requested a review from a team as a code owner July 16, 2026 13:12
Copilot AI review requested due to automatic review settings July 16, 2026 13:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents unbounded OID4VCI credential offers and binds REST-created pre-authorized codes to their originating sessions.

Changes:

  • Validates offer expiration and introduces long timestamps.
  • Revokes codes after logout, user disablement, or password changes.
  • Adds integration and SPI compatibility tests.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
CredentialOfferUriRequest.java Supports long expiration values.
OID4VCredentialOfferPreAuthTest.java Tests expiration and session revocation.
OID4VCBasicWallet.java Keeps originating sessions active during tests.
PreAuthorizedCodeGrantTypeTest.java Tests lifespan validation.
CredentialOfferProviderTest.java Tests SPI delegation.
PreAuthorizedCodeGrantType.java Validates lifespan and originating session.
VerifiableCredentialOfferAction.java Widens calculated expiration.
OID4VCIssuerEndpoint.java Bounds expiration and records session metadata.
DefaultCredentialOfferProvider.java Implements long expiration support.
CredentialOfferState.java Stores creation and originating-session metadata.
CredentialOfferProvider.java Adds a compatible long overload.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings July 16, 2026 15:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 17, 2026 08:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 17, 2026 13:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings July 17, 2026 14:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 20, 2026 09:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

services/src/main/java/org/keycloak/protocol/oid4vc/issuance/OID4VCIssuerEndpoint.java:571

  • Legacy stateless access tokens decode to UNKNOWN; bearer authentication then reconstructs a transient session for non-service-account users, but this check treats it as persistent and stores a request-scoped session ID that can never be resolved, so the resulting pre-authorized code always fails redemption. For UNKNOWN, fall back to the reconstructed session's persistence state and CREATED_FROM_PERSISTENT note before binding it.
                AccessTokenContext.SessionType originatingSessionType = session
                        .getProvider(TokenContextEncoderProvider.class)
                        .getTokenContextFromTokenId(getAuthResult().token().getId())
                        .getSessionType();
                boolean transientUserSession = originatingSessionType == AccessTokenContext.SessionType.TRANSIENT;

Copilot AI review requested due to automatic review settings July 21, 2026 07:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated no new comments.

@keycloak-github-bot keycloak-github-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreported flaky test detected, please review

@keycloak-github-bot

Copy link
Copy Markdown

Unreported flaky test detected

If the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR.

org.keycloak.testsuite.forms.BrowserFlowTest#testUserWithOneAdditionalFactorOtpSuccess

Keycloak CI - Base IT (5)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

org.keycloak.testsuite.forms.MultipleTabsLoginTest#multipleTabsParallelLoginTestWithAuthSessionExpiredAndRequiredAction

Keycloak CI - Forms IT (chrome)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

org.keycloak.testsuite.forms.MultipleTabsLoginTest#multipleTabsParallelLoginTestWithAuthSessionExpiredAndRegisterClick

Keycloak CI - Forms IT (chrome)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

Copilot AI review requested due to automatic review settings July 21, 2026 09:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

services/src/main/java/org/keycloak/protocol/oid4vc/issuance/OID4VCIssuerEndpoint.java:571

  • Legacy/unencoded token IDs produce SessionType.UNKNOWN; when such a normal-user token has no session ID, UserSessionUtil.java:86-88 reconstructs a transient request-scoped session. This check then binds that ephemeral ID, so the resulting offer can never be redeemed; include the actual session persistence state when handling UNKNOWN.
                boolean transientUserSession = originatingSessionType == AccessTokenContext.SessionType.TRANSIENT;

@keycloak-github-bot keycloak-github-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreported flaky test detected, please review

@keycloak-github-bot

Copy link
Copy Markdown

Unreported flaky test detected

If the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR.

org.keycloak.testsuite.forms.BrowserFlowTest#testUserWithOneAdditionalFactorOtpSuccess

Keycloak CI - Base IT (5)

org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
...

Report flaky test

Copilot AI review requested due to automatic review settings July 22, 2026 08:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.

Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com>
Copilot AI review requested due to automatic review settings July 22, 2026 09:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.

Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com>
Copilot AI review requested due to automatic review settings July 22, 2026 09:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 6 comments.

Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com>
Copilot AI review requested due to automatic review settings July 22, 2026 10:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OID4VCI: Unbounded expire parameter on /create-credential-offer allows indefinite pre-auth codes

2 participants