Skip to content

[OID4VCI] TokenResponse requires credential_identifiers in authorization_details#47404

Merged
mposolda merged 3 commits intokeycloak:mainfrom
tdiesler:ghi47386
Apr 9, 2026
Merged

[OID4VCI] TokenResponse requires credential_identifiers in authorization_details#47404
mposolda merged 3 commits intokeycloak:mainfrom
tdiesler:ghi47386

Conversation

@tdiesler
Copy link
Copy Markdown
Contributor

@tdiesler tdiesler commented Mar 24, 2026

closes #47386

Copy link
Copy Markdown

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

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

@tdiesler tdiesler force-pushed the ghi47386 branch 6 times, most recently from 421e8cb to 7139c38 Compare April 1, 2026 14:24
Copy link
Copy Markdown
Contributor

@forkimenjeckayang forkimenjeckayang left a comment

Choose a reason for hiding this comment

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

A few concerns @tdiesler
Please take a look when you can

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.

checkAuthorizationDetails() and validateAuthorizationDetail() apply different rules to request-time credential_identifiers (authorization rejects any presence, while the token path rejects only non-empty arrays), which can lead to divergent behavior (e.g., []).

Per Section 5.1.1, additional fields for openid_credential should not invalidate the authorization details type. Could we unify both paths by accepting this field on input and ignoring/clearing it, while ensuring token responses still emit server-authoritative credential_identifiers as defined in Section 6.2?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, additional fields should not invalidate the authorization details. However, this is a field not totally unknown to the spec - it's a known field used in the wrong context.

On that basis, I suggest we align like this ...

        if (credentialIdentifiers != null) {
            // we also reject an empty array of credential identifiers
            logger.warnf("Property credential_identifiers not allowed in authorization_details");
            throw getInvalidRequestException("credential_identifiers not allowed");
        }

It is unlikely that the conformance tests want to see the empty array pass.

WDYT?

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.

+1

@tdiesler tdiesler force-pushed the ghi47386 branch 7 times, most recently from 4c14d33 to d503f21 Compare April 7, 2026 09:27
Copy link
Copy Markdown
Contributor

@mposolda mposolda left a comment

Choose a reason for hiding this comment

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

@tdiesler Thanks! Added comment inline (related also to other comment by @forkimenjeckayang ).

Also one question: As mentioned here in this comment #47386 (comment) , we do not need to support credential_configuration_id parameter in the credential-request. However in this PR it is still supported. Any issues with removing support for credential_configuration_id in this PR? Or do you rather want to do as a follow-up?

throw new AuthorizationCheckException(Response.Status.BAD_REQUEST, Errors.INVALID_REQUEST,
"Cannot parse authorization_details: " + authDetailsParam);
}
for (AuthorizationDetailsJSONRepresentation authDetailJson : authDetails) {
Copy link
Copy Markdown
Contributor

@mposolda mposolda Apr 7, 2026

Choose a reason for hiding this comment

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

It will be nice if AuthorizationEndpointChecker does not have any direct dependencies on OID4VCI specific logic.

Is it possible to add new callback method to AuthorizationDetailsProcessorManager and AuthorizationDetailsProcessor, which will move this logic (lines 251-266) to the OID4VC specific processor? That can possibly help that we would be easily able to re-use same/similar validation like already done for token-endpoint? (As discussed in the other comment).

Copy link
Copy Markdown
Contributor Author

@tdiesler tdiesler Apr 8, 2026

Choose a reason for hiding this comment

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

yes, that's how it should be (done)

@tdiesler
Copy link
Copy Markdown
Contributor Author

tdiesler commented Apr 8, 2026

Any issues with removing support for credential_configuration_id in this PR? Or do you rather want to do as a follow-up

It is infact not supported, because of ...

        // Verify that the requested credential_configuration_id in the request matches one in the authorization_details
        //
        if (!Strings.isEmpty(requestedCredentialConfigurationId)) {

            if (!authorizedCredentialConfigurationId.equals(requestedCredentialConfigurationId)) {
                var errorMessage = "Credential configuration '" + requestedCredentialConfigurationId + "' not found in authorization_details";
                LOGGER.debug(errorMessage);
                eventBuilder.detail(Details.REASON, errorMessage).error(ErrorType.UNKNOWN_CREDENTIAL_CONFIGURATION.getValue());
                throw new BadRequestException(getErrorResponse(ErrorType.UNKNOWN_CREDENTIAL_CONFIGURATION, errorMessage));
            }

            if (!authorizedCredentialIdentifiers.isEmpty()) {
                var errorMessage = "Credential must be requested by credential identifier from authorization_details: " + authorizedCredentialIdentifiers;
                LOGGER.debug(errorMessage);
                eventBuilder.detail(Details.REASON, errorMessage).error(ErrorType.INVALID_CREDENTIAL_REQUEST.getValue());
                throw new BadRequestException(getErrorResponse(ErrorType.INVALID_CREDENTIAL_REQUEST, errorMessage));
            }
        }

The conformance suite suite wants to see an UNKNOWN_CREDENTIAL_CONFIGURATION error, so we can't simply fail on any credential_configuration_id.

In our case, it always fails because we always return authorization_details from the token endpoint which MUST contain a credential_identifier. Remember, we decided to do it that way even for scope only requests that have no credential_identifiers configured on the scope - (in which case we generate the credential_identifier <= credential_configuration_id_0000).

This code would stay valid even if we decide to no longer return redundant authorization_details from the token endpoint

tdiesler added 2 commits April 8, 2026 12:52
-- require well formed authorization details
-- thanks @forkimenjeckayang

Signed-off-by: Thomas Diesler <[email protected]>
@tdiesler tdiesler force-pushed the ghi47386 branch 2 times, most recently from 25f5102 to ccab662 Compare April 8, 2026 11:47
@mposolda mposolda self-assigned this Apr 8, 2026
Copy link
Copy Markdown
Contributor

@mposolda mposolda left a comment

Choose a reason for hiding this comment

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

@tdiesler Thanks for the clarifications.

Leaving PR open for one more day in case @forkimenjeckayang has any additional feedback.

@tdiesler
Copy link
Copy Markdown
Contributor Author

tdiesler commented Apr 8, 2026

@mposolda FYI, this PR introduces a considerable amount of ugliness related to #47649. Invalid authorization requests are now caught early and will timeout with that Selenium exception - the root cause is lost. In case you prefer that this does not enter the code base, have a look at PR #47850. If that gets merged first, our tests could also be restored to handle their invalid auth requests properly.

git grep 'TODO #47649' 

tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/OID4VCAuthorizationCodeFlowTestBase.java:        // [TODO #47649] OAuthClient cannot handle invalid authorization requests
tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/OID4VCAuthorizationCodeFlowTestBase.java:        // [TODO #47649] OAuthClient cannot handle invalid authorization requests
tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCAuthorizationDetailsFlowTestBase.java:        // [TODO #47649] OAuthClient cannot handle invalid authorization requests
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oid4vc/issuance/signing/OID4VCAuthorizationCodeFlowWithPARTest.java:        // [TODO #47649] OAuthClient cannot handle i

In LoginUrlBuilder the relevant change is this ...

    public AuthorizationEndpointResponse doLogin(String username, String password) {
        open();

        // Login page may not get displayed (e.g. in case of an invalid AuthorizationRequest)
        String currUrl = client.driver.getCurrentUrl();
        if (currUrl != null && !currUrl.contains("error=") && !currUrl.contains("error_description=")) {
            client.fillLoginForm(username, password);
        }
        return client.parseLoginResponse();
    }

Copy link
Copy Markdown
Contributor

@forkimenjeckayang forkimenjeckayang left a comment

Choose a reason for hiding this comment

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

No further concerns, approach LGTM

@mposolda
Copy link
Copy Markdown
Contributor

mposolda commented Apr 9, 2026

@tdiesler @forkimenjeckayang Thanks!

@mposolda mposolda merged commit 6fe5876 into keycloak:main Apr 9, 2026
84 checks passed
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] TokenResponse requires credential_identifiers in authorization_details

3 participants