{"record":{"id":"0c941cc7d4f922af","repo":"spring-projects/spring-security","slug":"autologin-failed-due-to-data-access-problem","errorCode":null,"errorMessage":"Autologin failed due to data access problem","messagePattern":"Autologin failed due to data access problem","errorType":"exception","errorClass":"RememberMeAuthenticationException","httpStatus":null,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java","lineNumber":133,"sourceCode":"\t\t\t\t\t\"PersistentTokenBasedRememberMeServices.cookieStolen\",\n\t\t\t\t\t\"Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.\"));\n\t\t}\n\t\tif (token.getDate().getTime() + getTokenValiditySeconds() * 1000L < System.currentTimeMillis()) {\n\t\t\tthrow new RememberMeAuthenticationException(\"Remember-me login has expired\");\n\t\t}\n\t\t// Token also matches, so login is valid. Update the token value, keeping the\n\t\t// *same* series number.\n\t\tthis.logger.debug(LogMessage.format(\"Refreshing persistent login token for user '%s', series '%s'\",\n\t\t\t\ttoken.getUsername(), token.getSeries()));\n\t\tPersistentRememberMeToken newToken = new PersistentRememberMeToken(token.getUsername(), token.getSeries(),\n\t\t\t\tgenerateTokenData(), new Date());\n\t\ttry {\n\t\t\tthis.tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate());\n\t\t\taddCookie(newToken, request, response);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.logger.error(\"Failed to update token: \", ex);\n\t\t\tthrow new RememberMeAuthenticationException(\"Autologin failed due to data access problem\");\n\t\t}\n\t\treturn getUserDetailsService().loadUserByUsername(token.getUsername());\n\t}\n\n\t/**\n\t * Creates a new persistent login token with a new series number, stores the data in\n\t * the persistent token repository and adds the corresponding cookie to the response.\n\t *\n\t */\n\t@Override\n\tprotected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response,\n\t\t\tAuthentication successfulAuthentication) {\n\t\tString username = successfulAuthentication.getName();\n\t\tthis.logger.debug(LogMessage.format(\"Creating new persistent login for user %s\", username));\n\t\tPersistentRememberMeToken persistentToken = new PersistentRememberMeToken(username, generateSeriesData(),\n\t\t\t\tgenerateTokenData(), new Date());\n\t\ttry {\n\t\t\tthis.tokenRepository.createNewToken(persistentToken);","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java#L115-L151","documentation":"PersistentTokenBasedRememberMeServices wraps any exception raised while persisting the rotated remember-me token (series/token value/date) into a RememberMeAuthenticationException with this message. The library cannot guarantee auto-login correctness if the new token cannot be written, so it aborts the remember-me authentication. The original data-access exception is logged via logger.error(\"Failed to update token: \", ex).","triggerScenarios":"processAutoLoginCookie calls tokenRepository.updateToken(series, tokenValue, date) during automatic login; if that call throws (DB down, table missing, constraint violation, connection timeout), the catch block rethrows this RememberMeAuthenticationException.","commonSituations":"Remember-me persistence table (persistent_logins) missing or schema mismatch; database connection pool exhausted or DB unreachable; the series row was deleted concurrently (another device logged in and rotated the token); JdbcTemplate token repository misconfigured with a broken DataSource.","solutions":["Check application logs for the 'Failed to update token: ' cause to identify the underlying data-access exception","Verify the persistent_logins table exists with columns username, series, token_value, last_used matching the schema in the reference docs","Confirm the DataSource used by JdbcTokenRepositoryImpl (or custom PersistentTokenRepository) is healthy and reachable","If using an in-memory/custom repository, ensure updateToken handles unknown series gracefully and that concurrent logins are not deleting rows","As a last resort clear stale cookies and have users log in again"],"exampleFix":"// before\n@Bean\npublic PersistentTokenRepository tokenRepository(DataSource ds) {\n    JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();\n    repo.setDataSource(ds); // table missing -> updateToken fails at autologin\n    return repo;\n}\n// after\n@Bean\npublic PersistentTokenRepository tokenRepository(DataSource ds) {\n    JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();\n    repo.setDataSource(ds);\n    repo.setCreateTableOnStartup(true); // creates persistent_logins if absent\n    return repo;\n}","handlingStrategy":"try-catch","validationCode":"// verify repository/table before autologin is relied upon\ntry (Connection c = dataSource.getConnection();\n     PreparedStatement ps = c.prepareStatement(\"SELECT 1 FROM persistent_logins LIMIT 1\")) {\n    ps.executeQuery();\n} catch (SQLException e) {\n    throw new IllegalStateException(\"persistent_logins table unavailable\", e);\n}","typeGuard":"boolean isTokenRepositoryHealthy(PersistentTokenRepository repo) {\n    return repo != null; // plus a DB connectivity probe at startup\n}","tryCatchPattern":"try {\n    SecurityContext ctx = SecurityContextHolder.getContext();\n    // ... auto-login flow\n} catch (RememberMeAuthenticationException e) {\n    logger.warn(\"Remember-me autologin failed; falling back to login page\", e);\n    response.sendRedirect(\"/login\");\n}","preventionTips":["Apply the reference schema for persistent_logins at deploy time","Monitor DB connectivity and pool exhaustion alerts","Don't delete token rows on every logout if multiple devices share the account","Log the underlying cause from 'Failed to update token:' and alert on it"],"tags":["remember-me","spring-security","database","authentication"],"backgroundTag":"database-write-failed","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}