JwtAuthenticationToken cannot be cast to OAuth2AuthenticationToken

I’m trying to follow this example to pass the access token from an Angular client to proxied routes from the zuul api gateway. However, in my AuthorizationHeaderFilter class:

@component
public class AuthorizationHeaderFilter extends ZuulFilter {
    private final OAuth2AuthorizedClientService authClientService;

    public AuthorizationHeaderFilter(OAuth2AuthorizedClientService authClientService) {
	this.authClientService = authClientService;
    }

    @Override
    public boolean shouldFilter() {
	return true;
    }

    @Override
    public Object run() throws ZuulException {
	RequestContext requestContext = RequestContext.getCurrentContext();
	Optional<String> authorizationHeader = getAuthorizationHeader();
	authorizationHeader.ifPresent(s -> requestContext.addZuulRequestHeader("Authorization", s));
	return null;
    }

    private Optional<String> getAuthorizationHeader() {
	Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
	OAuth2AuthenticationToken authToken = (OAuth2AuthenticationToken) authentication;	
	OAuth2AuthorizedClient authClient = authClientService.loadAuthorizedClient(
											authToken.getAuthorizedClientRegistrationId(),
											authToken.getName());
	OAuth2AccessToken authAccessToken = authClient.getAccessToken();
	if(authAccessToken == null) {
		return Optional.empty();
	} else {
		String tokenType = authAccessToken.getTokenType().getValue();
		String authorizationHeaderValue = String.format("%s %s", tokenType, authAccessToken.getTokenValue());
		return Optional.of(authorizationHeaderValue);
	}
    }

    @Override
    public String filterType() {
	return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
	return Ordered.LOWEST_PRECEDENCE;
    }
}

the SecurityContextHolder seems to be returning a JwtAuthenticationToken object instead of the expected OAuth2AuthenticationToken object as I’m getting the following exception:

Caused by: java.lang.ClassCastException:
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken
cannot be cast to
org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken

How can I use the JwtAuthenticationToken along with the OAuth2AuthorizedClientService to get the access token?

You should be able get the attributes from either token type using logic like the following:

Authentication authToken = SecurityContextHolder.getContext().getAuthentication();
Map<String, Object> attributes;
if (authToken instanceof OAuth2AuthenticationToken) {
    attributes = ((OAuth2AuthenticationToken) authToken).getPrincipal().getAttributes();
} else if (authToken instanceof JwtAuthenticationToken) {
    attributes = ((JwtAuthenticationToken) authToken).getTokenAttributes();
}
2 Likes

Thank you very much!

I’m curious about this.

Under which circumstances is an OAuth2AuthenticationToken provided, and under which is it JwtAuthenticationToken?

In other words, what determines which type of token the Authentication object is?

If you use oauth2Login(), the result will be a OAuth2AuthenticationToken. If you use resourceServer() for Spring Security, it will be a JwtAuthenticationToken.

3 Likes

@mraible I am using okta spring boot starter. When I access my api from browser I get OAuth2AuthenticationToken. When I access it from Postman I get JwtAuthenticationToken. Security confi g is the default form okta starter which is:

 @Bean
        SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception {
            // as of Spring Security 5.4 the default chain uses oauth2Login OR a JWT resource server (NOT both)
            // this does the same as both defaults merged together (and provides the previous behavior)
            http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
            http.oauth2Login();
            http.oauth2Client();
            http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
            return http.build();
        }

Do you happen to know what this differentiation relates to?

If you access your app via a browser, Spring Security’s oauth2Login() is invoked, and you’re redirected to Okta. Auth Code flow + PKCE is used and Spring Security will process the ID token to configure the user and create a OAuth2AuthenticationToken.

When you access from Postman (or the command like using something like cURL or HTTPie), you’re sending an Authorization header and oauth2ResourceServer() is invoked. Spring Security uses the JWT that’s passed in to establish your identity and create JwtAuthenticationToken. It does not process an ID token (because there isn’t one) or do a /userinfo lookup. You can write custom code to do a /userinfo lookup if you want, but you have to do it manually.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.