Remember-Me

Two Implementations

Remember-me keeps a user logged in across browser restarts with a long-lived cookie. It applies to session-based (form login) apps, not to JWT APIs.

TypeCookie containsLogout everywhere?Use
Simple hash-basedusername + expiry + hash(username, expiry, password, key)only by changing the passwordsmall apps
Persistent tokenrandom series + random token, stored in a DB tableyes, delete the rowsrecommended

Persistent Remember-Me

CREATE TABLE persistent_logins (
    username  VARCHAR(64) NOT NULL,
    series    VARCHAR(64) PRIMARY KEY,
    token     VARCHAR(64) NOT NULL,
    last_used TIMESTAMP   NOT NULL
);
@Bean
PersistentTokenRepository persistentTokenRepository(DataSource dataSource) {
    JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();
    repo.setDataSource(dataSource);
    return repo;
}

@Bean
SecurityFilterChain web(HttpSecurity http, PersistentTokenRepository tokens,
                        UserDetailsService users) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/seller/payouts/**").fullyAuthenticated()   // re-login required
            .requestMatchers("/seller/**").hasRole("SELLER")
            .anyRequest().permitAll())
        .formLogin(Customizer.withDefaults())
        .rememberMe(rm -> rm
            .tokenRepository(tokens)
            .userDetailsService(users)
            .tokenValiditySeconds((int) Duration.ofDays(14).toSeconds())
            .rememberMeParameter("remember-me"))                       // checkbox name on the form
        .logout(logout -> logout.deleteCookies("JSESSIONID", "remember-me"));
    return http.build();
}

Tip: fullyAuthenticated() rejects users who arrived only via the remember-me cookie. Use it for sensitive pages (payouts, changing email or password) so a stolen cookie is not enough.