{"record":{"id":"d58c2148d799bb4f","repo":"spring-projects/spring-security","slug":"invalid-token-d58c21","errorCode":"invalid_token","errorMessage":"Unable to authenticate the DPoP-bound access token.","messagePattern":"Unable to authenticate the DPoP-bound access token\\.","errorType":"error_code","errorClass":"OAuth2AuthenticationException","httpStatus":401,"severity":"error","filePath":"oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java","lineNumber":84,"sourceCode":"\t}\n\n\t@Override\n\tpublic Authentication authenticate(Authentication authentication) throws AuthenticationException {\n\t\tDPoPAuthenticationToken dPoPAuthenticationToken = (DPoPAuthenticationToken) authentication;\n\n\t\tBearerTokenAuthenticationToken accessTokenAuthenticationRequest = new BearerTokenAuthenticationToken(\n\t\t\t\tdPoPAuthenticationToken.getAccessToken());\n\t\tAuthentication accessTokenAuthenticationResult = this.tokenAuthenticationManager\n\t\t\t.authenticate(accessTokenAuthenticationRequest);\n\n\t\tAbstractOAuth2TokenAuthenticationToken<OAuth2Token> accessTokenAuthentication = null;\n\t\tif (accessTokenAuthenticationResult instanceof AbstractOAuth2TokenAuthenticationToken) {\n\t\t\taccessTokenAuthentication = (AbstractOAuth2TokenAuthenticationToken) accessTokenAuthenticationResult;\n\t\t}\n\t\tif (accessTokenAuthentication == null) {\n\t\t\tOAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN,\n\t\t\t\t\t\"Unable to authenticate the DPoP-bound access token.\", null);\n\t\t\tthrow new OAuth2AuthenticationException(error);\n\t\t}\n\n\t\tOAuth2AccessTokenClaims accessToken = new OAuth2AccessTokenClaims(accessTokenAuthentication.getToken(),\n\t\t\t\taccessTokenAuthentication.getTokenAttributes());\n\n\t\tDPoPProofContext dPoPProofContext = DPoPProofContext.withDPoPProof(dPoPAuthenticationToken.getDPoPProof())\n\t\t\t.accessToken(accessToken)\n\t\t\t.method(dPoPAuthenticationToken.getMethod())\n\t\t\t.targetUri(dPoPAuthenticationToken.getResourceUri())\n\t\t\t.build();\n\t\tJwtDecoder dPoPProofVerifier = this.dPoPProofVerifierFactory.createDecoder(dPoPProofContext);\n\n\t\ttry {\n\t\t\tdPoPProofVerifier.decode(dPoPProofContext.getDPoPProof());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tOAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_DPOP_PROOF);\n\t\t\tthrow new OAuth2AuthenticationException(error, ex);","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DPoPAuthenticationProvider.java#L66-L102","documentation":"DPoPAuthenticationProvider.authenticate() first authenticates the bearer access token with the delegate JwtAuthenticationProvider/OpaqueTokenAuthenticationProvider. If that delegate returns null (or a result that is not an AbstractOAuth2TokenAuthenticationToken), the provider cannot proceed to DPoP proof verification and throws OAuth2AuthenticationException with error code invalid_token and message 'Unable to authenticate the DPoP-bound access token.'","triggerScenarios":"The DPoP-bound access token itself fails delegated authentication (invalid JWT, expired, wrong issuer/audience) so the delegate yields null; the DPoPAuthenticationProvider is wired with a delegate that cannot authenticate the presented token type.","commonSituations":"Resource server configured for DPoP but the JWT decoder rejects the token upstream; token expired or revoked; the delegate provider's decoder/introspector misconfigured for the issuer; clients sending a non-DPoP token to a DPoP-protected endpoint.","solutions":["Fix the underlying access-token failure first (decode the token to see why it is rejected: signature, expiry, issuer, audience)","Ensure the delegate (JwtAuthenticationProvider or OpaqueTokenAuthenticationProvider) is correctly configured with the right decoder/introspector","Verify the client is sending a valid, unexpired DPoP-bound access token","Check that DPoPAuthenticationProvider is registered after the token provider in the OAuth2ResourceServer configuration"],"exampleFix":"// before\nhttp.oauth2ResourceServer(rs -> rs.jwt());\n// after\nhttp.oauth2ResourceServer(rs -> rs.jwt()\n    .jwtAuthenticationProvider(new DPoPAuthenticationProvider(jwtAuthProvider, dPoPProofVerifier)));","handlingStrategy":"try-catch","validationCode":"// resource server: confirm decoder config before wiring DPoP\n// assert issuer/jwkSetUri reachable and algorithms match the AS\n","typeGuard":null,"tryCatchPattern":"try {\n    authenticationManager.authenticate(new BearerTokenAuthenticationToken(token));\n} catch (OAuth2AuthenticationException e) {\n    if (\"invalid_token\".equals(e.getError().getErrorCode())) {\n        log.warn(\"DPoP-bound access token rejected: {}\", e.getError().getDescription());\n    }\n    throw e;\n}","preventionTips":["Keep the delegate token provider correctly configured (decoder/introspector) for the issuer","Monitor token expiry and refresh before calls to DPoP-protected endpoints","Verify with a known-good token that delegated authentication works before enabling DPoP"],"tags":["oauth2","dpop","bearer-token","authentication"],"backgroundTag":"invalid-bearer-token","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"}