I would like to avoid leaving a login session open after an OAuth2 authorization code (spring-authorization-server) has been issued. Currently the flow looks like this:
/oauth2/authorize
with a redirect_uri
./login
. The original request URL is saved in a session./oauth2/authorize
will see the authenticated session and redirect the user back to the redirect_uri
with a code.The session then remains, allowing the user to keep fetching new access tokens without re-authenticating.
Using stateless session management, I’ve toyed with CookieRequestCache to keep track of the original request URL in step 2. This works, but I would need some sort of internal redirect between step 3 and 4 or else the authentication state get lost. The browser would then be redirected from /login
straight to redirect_uri
. Is there a way to do this?
And if all else fails, is there way to write a hook that executes just prior to the redirect to redirect_uri
, deleting the session?
You can customize the response handling of /oauth2/authorize
in Spring Authorization Server through its OAuth2AuthorizationEndpointConfigurer
DSL.
You can take a look at authorizationResponseHandler
. A custom version could invalidate the session.
That said, requesting to immediately log out the user is a bit uncommon. Indeed, a common use case for an authorization server is to provide single-sign-on across multiple applications. If you choose to invalidate the session, then when the user visits a second application (perhaps introduced down the road), then they will need to log in again for each application that they visit.
With that caveat in mind, here is an example of what a custom AuthenticationSuccessHandler
could look like:
public class MySessionInvalidatingAuthorizationResponseHandler
implements AuthenticationSuccessHandler {
private final var redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
var result = (OAuth2AuthorizationCodeRequestAuthenticationToken)
authentication;
var code = result.getAuthorizationCode().getTokenValue();
var builder = UriComponentsBuilder
.fromUriString(result.getRedirectUri())
.queryParam(OAuth2ParameterNames.CODE, code);
if (StringUtils.hasText(result.getState())) {
builder.queryParam(OAuth2ParameterNames.STATE, result.getState());
}
// invalidate the session ...
this.redirectStrategy.sendRedirect(
request, response, builder.toUriString());
}
}
Alternatively, you could implement SecurityContextRepository
to store the SecurityContext
in a cookie; however, this comes with a still stronger caveat that storing the security context as a cookie is much harder to secure. In this setup, /oauth2/authorize
would work by default since it would have a materialized SecurityContext
available. This may be more of the same, though, since if your primary concern is immediately logging the individual out, you would still need to delete the cookie.
UPDATE: One additional thought is that maybe you are actually not wanting to log in the user at all. In that case, the client_credentials
flow may be more appropriate. It is a back-end grant flow where the client's id and password are used to get an access token.