{"record":{"id":"ac4f832a24ddba4d","repo":"spring-projects/spring-security","slug":"invalid-request-ac4f83","errorCode":"invalid_request","errorMessage":"OpenID Connect 1.0 Logout Request Parameter: id_token_hint","messagePattern":"OpenID Connect 1\\.0 Logout Request Parameter: id_token_hint","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":400,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/authentication/OidcLogoutAuthenticationConverter.java","lineNumber":63,"sourceCode":" * @see AuthenticationConverter\n * @see OidcLogoutAuthenticationToken\n * @see OidcLogoutEndpointFilter\n */\npublic final class OidcLogoutAuthenticationConverter implements AuthenticationConverter {\n\n\tprivate static final Authentication ANONYMOUS_AUTHENTICATION = new AnonymousAuthenticationToken(\"anonymous\",\n\t\t\t\"anonymousUser\", AuthorityUtils.createAuthorityList(\"ROLE_ANONYMOUS\"));\n\n\t@Override\n\tpublic Authentication convert(HttpServletRequest request) {\n\t\tMultiValueMap<String, String> parameters = \"GET\".equals(request.getMethod())\n\t\t\t\t? OAuth2EndpointUtils.getQueryParameters(request) : OAuth2EndpointUtils.getFormParameters(request);\n\n\t\t// id_token_hint (REQUIRED) // RECOMMENDED as per spec\n\t\tString idTokenHint = parameters.getFirst(\"id_token_hint\");\n\t\tList<String> idTokenHintParameters = parameters.get(\"id_token_hint\");\n\t\tif (!StringUtils.hasText(idTokenHint) || idTokenHintParameters == null || idTokenHintParameters.size() != 1) {\n\t\t\tthrow createException(OAuth2ErrorCodes.INVALID_REQUEST, \"id_token_hint\");\n\t\t}\n\n\t\tAuthentication principal = SecurityContextHolder.getContext().getAuthentication();\n\t\tif (principal == null) {\n\t\t\tprincipal = ANONYMOUS_AUTHENTICATION;\n\t\t}\n\n\t\tString sessionId = null;\n\t\tHttpSession session = request.getSession(false);\n\t\tif (session != null) {\n\t\t\tsessionId = session.getId();\n\t\t}\n\n\t\t// client_id (OPTIONAL)\n\t\tString clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);\n\t\tList<String> clientIdParameters = parameters.get(OAuth2ParameterNames.CLIENT_ID);\n\t\tif (StringUtils.hasText(clientId) && (clientIdParameters == null || clientIdParameters.size() != 1)) {\n\t\t\tthrow createException(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID);","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/web/authentication/OidcLogoutAuthenticationConverter.java#L45-L81","documentation":"OidcLogoutAuthenticationConverter requires the 'id_token_hint' parameter on the OIDC logout endpoint. Although the OIDC spec marks it RECOMMENDED, this converter treats it as REQUIRED: if the parameter is missing, blank, or supplied more than once, it throws an OAuth2AuthenticationException with error code 'invalid_request' naming 'id_token_hint'.","triggerScenarios":"GET/POST to the logout endpoint (default /logout with OidcLogoutEndpoint configured) without 'id_token_hint', with an empty value, or with duplicate 'id_token_hint' parameters in the query string or form body.","commonSituations":"Clients implementing RP-initiated logout that omit the hint, HTML forms submitting the parameter twice (e.g. hidden field plus query param), or proxies/redirects mangling the query string.","solutions":["Always include exactly one non-empty id_token_hint parameter pointing at a valid ID token from the RP session","Remove duplicate hidden form fields so the parameter appears only once","If you cannot supply a hint, use plain session logout instead of the OIDC logout endpoint"],"exampleFix":"// before\n<a href=\"/logout\">Log out</a>\n// after\n<a th:href=\"@{'/logout?id_token_hint=' + ${idToken}}\">Log out</a>","handlingStrategy":"validation","validationCode":"String hint = request.getParameter(\"id_token_hint\");\nif (hint == null || hint.isBlank()) { throw new IllegalArgumentException(\"id_token_hint is required for OIDC logout\"); }","typeGuard":null,"tryCatchPattern":"try {\n    chain.doFilter(request, response);\n} catch (OAuth2AuthenticationException ex) {\n    if (\"id_token_hint\".equals(ex.getError().getUri()) || ex.getMessage().contains(\"id_token_hint\")) {\n        response.sendError(HttpServletResponse.SC_BAD_REQUEST, \"id_token_hint parameter is required\");\n    }\n}","preventionTips":["Render the logout link server-side with the ID token embedded","Avoid rendering both a form field and query parameter with the same name"],"tags":["oauth2","oidc","request-parameter","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}