org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.authenticate detects that nonce is invalid and throws exception, because it compares hashed nonce with raw nonce.

                OidcIdToken idToken = this.createOidcToken(clientRegistration, accessTokenResponse);
String requestNonce = (String)authorizationRequest.getAttribute("nonce");
                if (requestNonce != null) {​​​​​​​​
                    String nonceHash;
OAuth2Error oauth2Error;
                    try {​​​​​​​​
                        nonceHash = createHash(requestNonce);
}​​​​​​​​ catch (NoSuchAlgorithmException var13) {​​​​​​​​
                        oauth2Error = new OAuth2Error("invalid_nonce");
                        throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}​​​​​​​​
                    String nonceHashClaim = idToken.getNonce();
                    if (nonceHashClaim == null || !nonceHashClaim.equals(nonceHash)) {​​​​​​​​
                        oauth2Error = new OAuth2Error("invalid_nonce");
                        throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}​​​​​​​​
                }​​​​​​​​

The line seems to expect nonce in the id token to be hashed, but I dont find evidence of this hash requirement in OpenID Connect specification and the IDP I use does not hash the nonce.

String nonceHashClaim = idToken.getNonce();

I use spring-security-oauth2-client 5.3.4.RELEASE.

Comment From: jgrandja

@devnewton The nonce parameter is hashed in DefaultOAuth2AuthorizationRequestResolver.

The hashed nonce is then passed in the Authentication Request and the provider returns the hashed nonce (unmodified) in the ID Token, as per spec:

nonce OPTIONAL. String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values. For implementation notes, see Section 15.5.2.

In the implementation notes section:

The nonce parameter value needs to include per-session state and be unguessable to attackers. One method to achieve this for Web Server Clients is to store a cryptographically random value as an HttpOnly session cookie and use a cryptographic hash of the value as the nonce parameter. In that case, the nonce in the returned ID Token is compared to the hash of the session cookie to detect ID Token replay by third parties. A related method applicable to JavaScript Clients is to store the cryptographically random value in HTML5 local storage and use a cryptographic hash of this value.

I hope this makes sense?

I'm going to close this as the nonce validation is implemented to spec.

Comment From: ghost

Thank you !