{"record":{"id":"36f3f46e7a06b48e","repo":"spring-projects/spring-security","slug":"oauth-2-0-token-revocation-parameter-parametern","errorCode":null,"errorMessage":"OAuth 2.0 Token Revocation Parameter: ${parameterName}","messagePattern":"OAuth 2\\.0 Token Revocation Parameter: (.+?)","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":400,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2TokenRevocationAuthenticationConverter.java","lineNumber":79,"sourceCode":"\t\tAssert.notNull(token, \"token cannot be null\");\n\n\t\t// token_type_hint (OPTIONAL)\n\t\tString tokenTypeHint = parameters.getFirst(OAuth2ParameterNames.TOKEN_TYPE_HINT);\n\t\tList<String> tokenTypeHintParams = parameters.get(OAuth2ParameterNames.TOKEN_TYPE_HINT);\n\t\tif (StringUtils.hasText(tokenTypeHint) && tokenTypeHintParams != null && tokenTypeHintParams.size() != 1) {\n\t\t\tthrowError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.TOKEN_TYPE_HINT);\n\t\t}\n\n\t\tAuthentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();\n\t\tAssert.notNull(clientPrincipal, \"clientPrincipal cannot be null\");\n\n\t\treturn new OAuth2TokenRevocationAuthenticationToken(token, clientPrincipal, tokenTypeHint);\n\t}\n\n\tprivate static void throwError(String errorCode, String parameterName) {\n\t\tOAuth2Error error = new OAuth2Error(errorCode, \"OAuth 2.0 Token Revocation Parameter: \" + parameterName,\n\t\t\t\t\"https://datatracker.ietf.org/doc/html/rfc7009#section-2.1\");\n\t\tthrow new OAuth2AuthenticationException(error);\n\t}\n\n}\n","sourceCodeStart":61,"sourceCodeEnd":83,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2TokenRevocationAuthenticationConverter.java#L61-L83","documentation":"The OAuth2TokenRevocationAuthenticationConverter throws this when a Token Revocation request violates RFC 7009 section 2.1: the required 'token' parameter is missing or duplicated, or 'token_type_hint' is supplied more than once. The message embeds the offending parameterName. It is thrown as an OAuth2AuthenticationException from convert() and rendered as a standard OAuth2 error response.","triggerScenarios":"POST to /oauth2/revoke without the 'token' form parameter, with 'token' repeated, or with a duplicated/missing 'token_type_hint'; throwError is invoked from convert() during parameter validation.","commonSituations":"Client libraries that drop empty form fields when token is empty string; duplicated parameters after URL/form encoding bugs; gateways that merge query and body parameters causing duplicates; typos like 'tokens=' instead of 'token='.","solutions":["Send exactly one non-empty 'token' form parameter in the revocation POST body.","If using token_type_hint, send it at most once with value access_token or refresh_token.","Check the error detail for parameterName and log the outgoing request body to find duplicates or omissions.","Verify no intermediate proxy duplicates form fields."],"exampleFix":"// before\nawait fetch('/oauth2/revoke', { method: 'POST', body: 'token=&token=' }); // empty + duplicate\n// after\nawait fetch('/oauth2/revoke', { method: 'POST', body: 'token=' + encodeURIComponent(token) });","handlingStrategy":"validation","validationCode":"const params = new URLSearchParams(body);\nif (params.getAll('token').length !== 1 || !params.get('token')) {\n  throw new Error('revocation requires exactly one non-empty token parameter');\n}","typeGuard":"function isRevocationBody(body) {\n  const p = body instanceof URLSearchParams ? body : new URLSearchParams(body);\n  return p.getAll('token').length === 1 && p.get('token').length > 0;\n}","tryCatchPattern":"try {\n  await fetch('/oauth2/revoke', { method: 'POST', body });\n} catch (e) {\n  if (e instanceof OAuth2AuthenticationException || e.message.includes('invalid_request')) {\n    console.error('Revocation parameter error:', e.message);\n  }\n}","preventionTips":["Send the token as a single form field; skip token_type_hint unless required.","Guard against empty-string tokens before sending the revocation request.","Disable interceptors that might re-encode the body and duplicate fields.","Note RFC 7009: revocation endpoints typically return 200 even for invalid tokens, so a parameter-level invalid_request indicates a malformed request, not a bad token."],"tags":["oauth2","token-revocation","rfc7009","invalid-request"],"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"}