spring-cloud / spring-cloud/spring-cloud-gateway

TokenRelay bug when using different oauth2 client registration

Open
#3,535 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

waiting-for-triage
Dominant language
Java
Stars
4.9k
Forks
3.5k
Avg merge
20h 57m
Merged PRs (30d)
8

Description

spring-cloud-starter-gateway v4.1.5

When using a different client registration for the TokenRelay filter (like TokenRelay=someClientRegistrationId and not the one used for logging in the user), the Bearer auth header is not set. I think this is because the client used for the TokenRelay does not get an authorizedClient.

Example application security config:

  security:
    oauth2:
      client:
        provider:
          myAuthProvider:
            issuer-uri: ${issuerUri}
            user-name-attribute: name
        registration:
          loginClient:
            provider: myAuthProvider
            authorization-grant-type: authorization_code
            client-id: ${clientId}
            client-secret: ${clientSecret}
            scope: openid,profile,email,offline_access
          resourceClient:
            provider: myAuthProvider
            authorization-grant-type: client_credentials
            client-id: ${clientId}
            client-secret: ${clientSecret}
            scope: /.default
  cloud:
    gateway:
      routes:
        - id: resourceServerRoute
          uri: ${resouceServerUri}
          predicates:
            - Path=/resource/**
          filters:
            - TokenRelay=resourceClient

Suggested solution (inspired by https://docs.spring.io/spring-security/reference/reactive/oauth2/client/authorization-grants.html#_using_the_access_token):

In function TokenRelayGatewayFilterFactory.authorizationRequest add .attribute(ServerWebExchange.class.getName(), exchange) to the builder like so:

    private Mono<OAuth2AuthorizeRequest> authorizationRequest(String defaultClientRegistrationId,
                                                              Authentication principal,
                                                              ServerWebExchange exchange) {
        String clientRegistrationId = defaultClientRegistrationId;
        if (clientRegistrationId == null && principal instanceof OAuth2AuthenticationToken) {
            clientRegistrationId = ((OAuth2AuthenticationToken) principal).getAuthorizedClientRegistrationId();
        }
        return Mono.justOrEmpty(clientRegistrationId).map(OAuth2AuthorizeRequest::withClientRegistrationId)
                .map(builder -> builder.principal(principal).attribute(ServerWebExchange.class.getName(), exchange).build());
    }

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at TokenRelayGatewayFilterFactory.authorizationRequest and compare the OAuth2AuthorizeRequest builder with the Spring Security authorization-grants guidance linked in the issue. Reproduce the configuration using separate loginClient and resourceClient registrations, then verify that the resource route receives the expected Bearer authorization header.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring, spring-boot
Domain
api, authentication
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.