{"record":{"id":"b859bb8e07f03ede","repo":"spring-projects/spring-security","slug":"invalid-token-b859bb","errorCode":"invalid_token","errorMessage":"Invalid bearer token","messagePattern":"Invalid bearer token","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":401,"severity":"error","filePath":"oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java","lineNumber":187,"sourceCode":"\t\t\tthis.logger.trace(\"Sending to authentication entry point since failed to resolve bearer token\", invalid);\n\t\t\tthis.authenticationEntryPoint.commence(request, response, invalid);\n\t\t\treturn;\n\t\t}\n\n\t\tif (authenticationRequest == null) {\n\t\t\tthis.logger.trace(\"Did not process request since did not find bearer token\");\n\t\t\tfilterChain.doFilter(request, response);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tAuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request);\n\t\t\tAuthentication authenticationResult = authenticationManager.authenticate(authenticationRequest);\n\t\t\tif (isDPoPBoundAccessToken(authenticationResult)) {\n\t\t\t\t// Prevent downgraded usage of DPoP-bound access tokens,\n\t\t\t\t// by rejecting a DPoP-bound access token received as a bearer token.\n\t\t\t\tBearerTokenError error = BearerTokenErrors.invalidToken(\"Invalid bearer token\");\n\t\t\t\tthrow new OAuth2AuthenticationException(error);\n\t\t\t}\n\t\t\tAuthentication current = this.securityContextHolderStrategy.getContext().getAuthentication();\n\t\t\tif (current != null && current.isAuthenticated() && declaresToBuilder(authenticationResult)) {\n\t\t\t\tauthenticationResult = authenticationResult.toBuilder().authorities((a) -> {\n\t\t\t\t\tSet<String> newAuthorities = a.stream()\n\t\t\t\t\t\t.map(GrantedAuthority::getAuthority)\n\t\t\t\t\t\t.collect(Collectors.toUnmodifiableSet());\n\t\t\t\t\tfor (GrantedAuthority currentAuthority : current.getAuthorities()) {\n\t\t\t\t\t\tif (!newAuthorities.contains(currentAuthority.getAuthority())) {\n\t\t\t\t\t\t\ta.add(currentAuthority);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}).build();\n\t\t\t}\n\t\t\tSecurityContext context = this.securityContextHolderStrategy.createEmptyContext();\n\t\t\tcontext.setAuthentication(authenticationResult);\n\t\t\tthis.securityContextHolderStrategy.setContext(context);\n\t\t\tthis.securityContextRepository.saveContext(context, request, response);","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/authentication/BearerTokenAuthenticationFilter.java#L169-L205","documentation":"BearerTokenAuthenticationFilter throws this when authentication succeeds but the resulting access token is DPoP-bound while the request used it as a plain Bearer token. Spring Security rejects this downgrade to prevent a token issued for DPoP (proof-of-possession) usage from being replayed without the bound key proof. The error surfaces as OAuth2AuthenticationException with code invalid_token even though the token itself may be valid.","triggerScenarios":"A client obtains an access token bound to a DPoP key from the authorization server, then calls the resource server with 'Authorization: Bearer <token>' and no DPoP proof header. The filter detects the DPoP binding in the authenticated result (isDPoPBoundAccessToken) and rejects the request.","commonSituations":"Clients that previously used opaque/JWT bearer tokens switching to DPoP-issued tokens without updating their HTTP client; SDKs that don't support DPoP proof generation; token endpoint misconfiguration returning DPoP-bound tokens to bearer-only clients.","solutions":["Update the client to send a valid DPoP proof header (DPoP) with each request and use the 'DPoP' authorization scheme","Request a non-DPoP-bound (plain bearer) token from the authorization server for bearer-only clients","If you must accept DPoP tokens as bearer tokens (not recommended), customize the filter/authentication logic, understanding the security implications","Verify the authorization server client configuration (token_endpoint_auth binding) matches how the token will be used"],"exampleFix":"// before\nrequest.header(\"Authorization\", \"Bearer \" + accessToken);\n// after (client with DPoP support)\nString proof = dPoPSigner.generateProof(accessToken, httpMethod, url);\nrequest.header(\"Authorization\", \"DPoP \" + accessToken);\nrequest.header(\"DPoP\", proof);","handlingStrategy":"validation","validationCode":"if (tokenEndpointResponse.getAccessToken().getTokenType().getValue().equalsIgnoreCase(\"DPoP\")\n        && !clientSupportsDPoP) {\n    throw new IllegalStateException(\"Client received a DPoP-bound token but cannot send DPoP proofs\");\n}","typeGuard":"boolean isDpopBound(OAuth2AccessToken token) {\n    return \"DPoP\".equalsIgnoreCase(token.getTokenType().getValue());\n}","tryCatchPattern":"try {\n    return chain.filter(exchange);\n} catch (OAuth2AuthenticationException e) {\n    if (\"invalid_token\".equals(e.getError().getErrorCode())) {\n        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);\n    }\n    return Mono.error(e);\n}","preventionTips":["Match the token type requested at the token endpoint with the client's actual capabilities","If the client cannot do DPoP, request plain bearer tokens (aud/grant configuration)","Keep DPoP proof generation in one shared client interceptor so it is never skipped","Document at the authorization server which clients are DPoP-enabled"],"tags":["oauth2","dpop","bearer-token","spring-security"],"backgroundTag":"dpop-token-misuse","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"}