Skip to content

Simplify access to OAuth 2.0 token attributes #6498

Closed
@jzheaux

Description

@jzheaux

Related to #5200 and #6352 (comment)

We should introduce OAuth2TokenAttributes, a class that holds an OAuth 2.0 Token's attributes. To this point, each authentication token has exposed attributes simply as a Map.

It works out best, though, when an new class's usage can be demonstrated, ensuring that the API is correct. So, to complete this ticket, a few things need to be done:

  • Introduce OAuth2TokenAttributes

This is a simple domain object that contains a Map:

public class OAuth2TokenAttributes {
    <T> T getAttribute(String name);
    Map<String, Object> getAttributes();
}

It should probably go in oauth2-core in org.springframework.security.oauth2.core.

  • Change OAuth2IntrospectionAuthenticationToken's constructor

It should take an OAuth2TokenAttributes for its principal instead of a Map. While this is a breaking change, it's allowable since that API has not GA'd yet

  • Update the oauth2resourceserver-opaque sample

This sample should be adjusted to use the token's principal (OAuth2TokenAttributes)

Extra Background

Spring Security offers different ways to access OAuth 2.0 token attributes, depending on how they were obtained.

For example, a Resource Server can authenticate via JWT tokens and obtain their contents in the following way:

@GetMapping("/protected")
public String method(@AuthenticationPrincipal Jwt jwt) {
    String subject = jwt.getSubject();
    // ...
}

// and

@GetMapping("/protected")
public String method(@AuthenticationPrincipal(expression="subject") String subject) {
    // ...
}

When using introspection, though, the principal is simply a map, so the pattern is:

@GetMapping("/protected")
public String method(@AuthenticationPrincipal Map<String, Object> attributes) {
    String subject = (String) attributes.get("sub");
    // ...
}

// and 

@GetMapping("/protected")
public String method(@AuthenticationPrincipal(expression="['sub']") String subject) {
    // ...
}

It would be nice if application code didn't have to know the token verification strategy to extract the attributes from the principal.

Further, there is potentially some clean up here with clarifying the meaning around attributes and claims. Claims are unverified attributes. Or, in other words, a JWT has a claim set, but the ensuing Authentication object has attributes since the JWT at that point is verified.

There is already one way to get attributes in an agnostic way:

@GetMapping("/protected")
public String method(AbstractOAuth2TokenAuthenticationToken token) {
    String subject = (String) token.getTokenAttributes().get("sub");
    // ...
}

But it would be nicer if this were a bit simpler and users could take advantage of more Spring Security features agnostically.

By thinking more about the principal and how to expose it, it may be possible to achieve something like:

@GetMapping("/protected")
public String method(@AuthenticationPrincipal OAuth2TokenAttributes attributes) {
    String subject = attributes.getAttribute("sub");
    // ...
}

// and

@GetMapping("/protected")
public String method(@AuthenticationPrincipal(expression="attribute['sub']") String subject) {
    // ...
}

that works for any OAuth 2.0 Authentication type.

Metadata

Metadata

Assignees

No one assigned

    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