How-to: Remember-me with a Single Page Application
I’m posting this issue based on the excellent new how-to's issues….
I’m struggling with the “remember-me” feature (SPA context) and I don’t know if such topic is appropriate to the Spring Authorization Server.
I tried to setup the remember-me feature in the SecurityFilterChain. The cookie is created in the browser and the authentication is done later in the server, but the login page (a custom one) is always showed, instead of just redirect the authorization to the client.
- Is the remember-me feature appropriate with OAuth2 in a SPA with PKCE?
- Does Spring Authorization Server supports the remember-me feature? Is it possible?
- Is it a good idea to use refresh tokens to setup the remember-me? (with a longer expiricy and conditional to a checkbox on the login page)
- Is it possible to have a how-to about the remember-me feature?
Hi @clgraf!
Thanks for the questions. However, I'm going to go ahead and edit this to be a how-to guide request, relating to #4 above. As far as your other questions, I think they would be better suited to Stack Overflow. We prefer to use GitHub issues only for bugs and enhancements (in this case, how-to guides are enhancements for the docs). Feel free to update this issue with a link to the re-posted question(s) (so that other people can find it), and I'll be happy to take a look.
Related #499
I have a Idea.
To implement the “remember-me” feature , need to modify oauth2authorizationendpointconfigurer.class, put oauth2authorizationendpointfilter after remembermeauthenticationfilter.
Step1: modify OAuth2AuthorizationEndpointConfigurer.class's code of spring-authorization-server
// builder.addFilterBefore(postProcess(authorizationEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
builder.addFilterBefore(postProcess(authorizationEndpointFilter), ExceptionTranslationFilter.class);
Step2: Modify the default-authorizationserver's code in samples and test it
- Add rememberMe in
AuthorizationServerConfig.class
public class AuthorizationServerConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, UserDetailsService users) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
// @formatter:off
http
.exceptionHandling(exceptions ->
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
);
http.rememberMe((rememberMe) -> {
rememberMe.userDetailsService(users);
rememberMe.key("123");
});
// @formatter:on
return http.build();
}
- Add rememberMe in
DefaultSecurityConfig.class
public class DefaultSecurityConfig {
// @formatter:off
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, UserDetailsService users) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.formLogin(withDefaults());
http.rememberMe((rememberMe) -> {
rememberMe.userDetailsService(users);
rememberMe.key("123");
});
return http.build();
}
Step3: Test
-
run application
- run default-authorizationserver
- run messages-resource
- run messages-client
-
http://127.0.0.1:8080
@clgraf User Authentication is not a concern for Spring Authorization Server as its sole focus is OAuth2 Authorization. Spring Security is where you would configure User Authentication with whatever underlying mechanism you require.
If you look at the default-authorizationserver sample, you can configure the Remember-Me feature in the DefaultSecurityConfig, which ultimately is the Spring Security filter chain.
Here is a link to a Remember-Me sample you can review further.
I'm going to close this issue based on the provided explanation.
For what it's worth, we may be able to override the order from configuration instead of modifying the library, perhaps adding it after the LogoutFilter,
public class AuthorizationServerConfig {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, RememberMeAuthenticationFilter rememberMe) {
http.
...
.addFilterAfter(rememberMe, LogoutFilter.class)
....
return http.build();
}
@Bean
public RememberMeAuthenticationFilter rememberMeAuthenticationFilter(AuthenticationManager authenticationManager, RememberMeServices rememberMeServices) throws Exception {
return new RememberMeAuthenticationFilter(authenticationManager, rememberMeServices);
}