Skip to content

OidcAuthorizationCodeAuthenticationProvider is missing a FactorGrantedAuthority #19140

@louis-jaris

Description

@louis-jaris

Describe the bug
OidcAuthorizationCodeAuthenticationProvider is missing a FactorGrantedAuthority (similarly to OAuth2LoginAuthenticationProvider), which is causing issues later in the chain (when, in a Spring Authorization Server, we try to generate an id_token for a grant_type=authorization_code)

To Reproduce
The bug started to appear in Spring Security 7.0.5 (I traced it to this issue: #18282)

  1. Configure "OAuth2 Login" for our Spring Project (http.oauth2Login(...) — vanilla configuration)
    a. In your OAuth2 client configuration, set the scope openid email profile (for a Google OAuth2 client for example)
  2. Configure an Authorization Server http.oauth2AuthorizationServer(...) (vanilla should be fine too)
  3. Try to get an access_token + id_token from our local Authorization Server using a grant_type=authorization_code and scope=openid, by using our OAuth2 login configured (e.g. Google Login)

Expected behavior
Be able to retrieve an id_token + access_token.
But we are observing an API error indicating that auth_time cannot be null (because of the missing FactorGrantedAuthority that makes it way up to JwtGenerator, that is now (rightfully) awaiting a FactorGrantedAuthority to accurately compute the auth_time claim

Sample

Please find attached a screenshot of my debugger, just before that the JwtGenerator throws me an error because of the missing FactorGrantedAuthority
Image

How to mitigate / quick fix while the long term solution :

Inject a GrantedAuthoritiesMapper into OidcAuthorizationCodeAuthenticationProvider that is injecting FactorGrantedAuthority.AUTHORIZATION_CODE_AUTHORITY for us:

http.oauth2Login(oauth2Login ->
    oauth2Login.userInfoEndpoint(userInfo -> userInfo.userAuthoritiesMapper(bugFixOidcUserAuthoritiesMapper()))
);

// TODO remove once Spring Security 7.X contains the long term fix
private GrantedAuthoritiesMapper bugFixOidcUserAuthoritiesMapper() {
        return authorities -> {
            Set<GrantedAuthority> mapped = new LinkedHashSet<>(authorities);
            mapped.add(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.AUTHORIZATION_CODE_AUTHORITY));
            return mapped;
        };

On a final note, thanks a lot for your work guys ! 😄 🙏

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions