Skip to content

OAuth2 Client Credentials Flow: Getting access tokens in the service/data tier #6780

Closed
@fritzdj

Description

@fritzdj

Summary
Currently there is a way to auto-wire OAuth2AuthorizedClientService in a component in the service/data tier to lookup the OAuth2AuthorizedClient. This works, but you would still need to use OAuth2AuthorizedClientArgumentResolver to resolve OAuth2AuthorizedClient in web-tier first. My suggestion is to make things more self-contained in service/data tier by allowing OAuth2AuthorizedClientService to get new access tokens if needed. I think Spring should allow new access tokens to be retrieved either way (in service/data tier OR web tier). We tried this with a custom service bean and it is working using some of the logic in OAuth2AuthorizedClientArgumentResolver.

fyi @jgrandja - see #6609

Example
Here is an example of a bean that could be created and used by OAuth2AuthorizedClientArgumentResolver (in the web tier) OR used by a class in the service/data tier to get new access tokens. This also has a temporary workaround to get around #6609 (where access token is never refreshed).

public class OAuth2AuthorizedClientService {

    private ClientRegistrationRepository clientRegistrationRepository;
    private OAuth2AuthorizedClientRepository authorizedClientRepository;
    private HttpServletRequest httpServletRequest;
    private HttpServletResponse httpServletResponse;
    private DefaultClientCredentialsTokenResponseClient defaultClientCredentialsTokenResponseClient = new DefaultClientCredentialsTokenResponseClient();

    public OAuth2AuthorizedClientService(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientRepository authorizedClientRepository,
            HttpServletRequest httpServletRequest,
            HttpServletResponse httpServletResponse) {
        this.clientRegistrationRepository = clientRegistrationRepository;
        this.authorizedClientRepository = authorizedClientRepository;
        this.httpServletRequest = httpServletRequest;
        this.httpServletResponse = httpServletResponse;
    }

    public OAuth2AuthorizedClient getAuthorizedClient(String audience) {
        Authentication principal = SecurityContextHolder.getContext().getAuthentication();
        ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(audience);

        OAuth2AuthorizedClient authorizedClient = this.authorizedClientRepository.loadAuthorizedClient(
            audience, principal, httpServletRequest);
        if (authorizedClient != null && authorizedClient.getAccessToken().getExpiresAt().isAfter(Instant.now().plusSeconds(300))) {
            return authorizedClient;
        }

        OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest =
            new OAuth2ClientCredentialsGrantRequest(clientRegistration);

        defaultClientCredentialsTokenResponseClient
            .setRequestEntityConverter(new Auth0ClientCredentialsGrantRequestEntityConverter(
                audience));
        OAuth2AccessTokenResponse tokenResponse =
            defaultClientCredentialsTokenResponseClient.getTokenResponse(clientCredentialsGrantRequest);

        authorizedClient = new OAuth2AuthorizedClient(
            clientRegistration,
            principal.getName(),
            tokenResponse.getAccessToken());

        this.authorizedClientRepository.saveAuthorizedClient(
            authorizedClient,
            principal,
            httpServletRequest,
            httpServletResponse);

        return authorizedClient;
    }


    public void setDefaultClientCredentialsTokenResponseClient(DefaultClientCredentialsTokenResponseClient defaultClientCredentialsTokenResponseClient) {
        this.defaultClientCredentialsTokenResponseClient = defaultClientCredentialsTokenResponseClient;
    }
}

Metadata

Metadata

Assignees

Labels

in: oauth2An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions