Search code examples
javaspring-bootspring-securityjwtspring-authorization-server

Spring OAuth2AuthorizationService implementations persist JWT access tokens


I recently began developing an OAuth/OIC identity provider with Spring Boot 3, Spring Security 6, and Spring Authorization Server. I'm new to OAuth but have some experience with session-based web authentication, and generally understand JWTs.

My current plan to authenticate users is to issue opaque refresh tokens and self-contained JWT access tokens. This way, I get the benefit of being able to revoke the long lived refresh tokens at will (because they are checked against the server-side every time they're used), but the shorter-lived access tokens can be used and trusted without the client having to ask the server for anything (except the public signing key). The refresh token will be used every once in a while to request a new access token from the server when the old one expires.

While implementing this with Spring Authorization Server, I came across the OAuth2AuthorizationService interface. This interface will store OAuth2Authorization objects persistently (or in memory, depending on which implementation is used). OAuth2Authorization objects can contain both a refresh token and access token. Why do the both of these need to be stored with the OAuth2AuthorizationService?

If I was using an opaque access token it would make sense, but I'm using a JWT access token. so there's no benefit to storing them persistently because they are supposed to be trusted as-is until they expire. Clients aren't expected to check a JWT against the server, because that defeats the point of the token being self-contained!

Is there something I'm missing, or are the default implementations of OAuth2AuthorizationService just covering their bases by storing both tokens server-side, just in case you configured refresh tokens and access tokens to be opaque? I'm going to be storing my tokens server-side in a persistent Redis instance, so I don't want to waste space in memory unless I absolutely have to. Is it okay for my implementation of OAuth2AuthorizationService to just store refresh tokens and map them to a user's ID or information, then build the OAuth2Authorization object on the spot when it's requested?


Solution

  • OAuth2Authorization objects can contain both a refresh token and access token. Why do the both of these need to be stored with the OAuth2AuthorizationService?

    OAuth2AuthorizationService#findByToken(String token, OAuth2TokenType tokenType) is used by endpoints such as /oauth2/introspect and /oauth2/revoke, and is designed to support both access and refresh tokens.

    Clients aren't expected to check a JWT against the server, because that defeats the point of the token being self-contained!

    In some cases, clients may want to verify that the access token has not been revoked by calling /oauth2/introspect with each request, even when using JWTs. The /oauth2/introspect endpoint supports both opaque and JWT tokens.

    Sample RedisOAuth2AuthorizationService