bojackhorseman99
bojackhorseman99

Reputation: 329

Persist session after browser is closed

I have a NextJS application that uses a Backend for Frontend Architecture with Spring Security OAuth2 Client and Spring Cloud Gateway, which communicates to my Spring Authorization Server, very similar to this sample.

My webapp is working real nice, I'm getting the SESSION and X-CSRF token from my BFF and are being set in the browser on my NextJS app as cookies, so everything is cool to that point. But my doubt is that I closed the browser window and my session goes away, obviously it happens since both the cookies have MAX-AGE as "Session".

I know that the best practice is to let is as is, let the session either expire by the session timeout or when the browser session ends, but I'm curious to know how to persist the SESSION and X-CSRF cookies after the browser closes, so I have these questions:

  1. Is it just enough to set the MAX-AGE to something in both the BFF and Spring Authorization Server?
  2. Is Spring Security Remember Me needed? Though my BFF uses WebFlux Security so that functionality isn't available.
  3. Should the X-CSRF Cookie also be persisted after the browser is closed, just as the session?
  4. Should the session timeout equal the max age that I would set for both the cookies?
  5. Should the X-CSRF token be persisted in a database if I spun up multiple instances of the BFF?

Also I'm confused on how to setup this because of the fact that I do the login on the Spring Authorization Server but I'm also logged in in the BFF since I have the SESSION and X-CSRF token to communicate with my BFF, so I guess that both session configuration should be the same on these two apps since they both create a session cookie even though the browser only gets the BFF one.

Also worth noting that both my BFF and my Spring Authorization Server, use Spring Session with Redis using different namespaces.

Relevant Spring Security configuration in my BFF:

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    http
            .authorizeExchange(authorizeExchange ->
                    authorizeExchange.anyExchange().authenticated()
            )
            .exceptionHandling(exceptionHandling ->
                    exceptionHandling.authenticationEntryPoint(authenticationEntryPoint())
            )
            .csrf(csrf ->
                    csrf.csrfTokenRepository(csrfTokenRepository())
            )
            .cors(Customizer.withDefaults())
            .oauth2Login(oauth2 ->
                    oauth2.authenticationSuccessHandler(authenticationSuccessHandler())
            )
            .logout(logout ->
                    logout
                            .logoutHandler(logoutHandler())
                            .logoutSuccessHandler(logoutSuccessHandler())
            )
            .oauth2Client(Customizer.withDefaults());
    return http.build();
}

Security Configuration on my Spring Authorization Server:

// AuthorizationServerConfig class
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    return http.cors(Customizer.withDefaults())
            .formLogin(Customizer.withDefaults())
            .build();
}


// WebSecurityConfig class
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http
            .authorizeRequests(authorizeRequests ->
                    authorizeRequests.anyRequest().authenticated()
            )
            .cors(withDefaults())
            .formLogin(withDefaults());
    return http.build();
}

Upvotes: 2

Views: 810

Answers (1)

bojackhorseman99
bojackhorseman99

Reputation: 329

I've done some research and for folks looking for something similar this may shed a little bit of light.

To answer my own questions:

  1. Is it just enough to set the MAX-AGE to something in both the BFF and Spring Authorization Server?

I think that setting the max-age for my BFF for my session and x-csrf token is enough for enabling my users to be able to open my SPA again and be able to keep using the application freely without login in again.

You can find more information about how to set the max age when using Spring Security for servlet applications here or here for Reactive applications

I don't think that it makes sense to set the max age for the Spring Authorization Server microservice since the browser only gets and needs the one from the BFF Gateway microservice.

Also it is worth noting that I would guess that the session timeout should be equal or superior for what you set the max age, since when your users are away from the app the inactivity on the BFF would invalidate the session if it timeouts, more on that here

  1. Is Spring Security Remember Me needed? Though my BFF uses WebFlux Security so that functionality isn't available.

If you have a servlet application, Remember me does allow to auto login the user when they close the window back, in my case I use a Reactive application therefore this feature is not yet built in. But if yours is a servlet one, you can try the feature here

  1. Should the X-CSRF Cookie also be persisted after the browser is closed, just as the session?

I would think so, because it won't be generated back since you aren't automatically login on the app when you reopen the browser window, you are just still using the same session. This sounds like a bad practice but I haven't found what to do in this case.

You can set the max age for the X-CSRF token on both servlet and reactive applications by using CookieCsrfTokenRepository or CookieServerCsrfTokenRepository.

  1. Should the session timeout equal the max age that I would set for both the cookies?

Again I would think that the timeout should be equal or superior or depending of the time you would like to give the users to make time it out, since it refreshes every time someone does something on the server. Look more on that here

  1. Should the X-CSRF token be persisted in a database if I spun up multiple instances of the BFF?

I don't think so, since it appears that it's tied to the HTTPSession and you are using something like Spring Session and already storing that on the database, then I don't think that you should try to store it in a different way. More on that here

If anyone wants to add something more, or I said something wrong please correct it.

Upvotes: 2

Related Questions