prestodb/presto · error · ChallengeFailedException

Missing nonce

Error message

Missing nonce

What it means

NimbusOAuth2Client's OIDC authentication code flow requires a nonce (for replay protection bound into the ID token). getOAuth2Response throws ChallengeFailedException when the caller presents the authorization code without the nonce captured at challenge time.

Solutions

  1. Ensure the challenge step (startChallenge) stores the nonce and the callback passes it back via getOAuth2Response(code, callbackUri, Optional.of(nonce))
  2. Use sticky sessions / shared state store when running multiple coordinators behind a load balancer
  3. Clear stale oauth2 state cookies and retry the login flow in a single browser tab
  4. Check that the HttpServer authentication config consistently uses the OIDC (nonce) path

Example fix

// before
client.getOAuth2Response(code, callbackUri, Optional.empty());
// after
client.getOAuth2Response(code, callbackUri, Optional.of(savedNonce)); // nonce captured at challenge time
Defensive patterns

Strategy: validation

Validate before calling

if (nonce == null || nonce.isEmpty()) { throw new IllegalStateException("OAuth2 challenge state missing nonce; restart login flow"); }

Type guard

boolean hasNonce(java.util.Optional<String> nonce) { return nonce != null && nonce.isPresent() && !nonce.get().isEmpty(); }

Try / catch

try { return client.getOAuth2Response(code, callbackUri, nonce); } catch (ChallengeFailedException e) { restartAuthenticationChallenge(); throw e; }

Prevention

When it happens

Trigger: Completing the OAuth2 redirect flow where the nonce Optional passed to getOAuth2Response is empty — the challenge state was lost, the browser flow was initiated with nonce but the callback lost it, or authentication was initiated with a nonce-less flow but validated against an OIDC client requiring it.

Common situations: Server restart between challenge and callback wiping the nonce from the state store, multiple browser tabs interfering with the oauth2 state cookie, misconfigured load balancer routing callback to a different node that lacks the nonce state, or OAuth2Client configuration toggled from oauth2 to OIDC mid-flow.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/14af6def86281a5b. Report an issue: GitHub.

Appendix: source

Thrown at presto-main/src/main/java/com/facebook/presto/server/security/oauth2/NimbusOAuth2Client.java:342

        public Request createAuthorizationRequest(String state, URI callbackUri)
        {
            String nonce = new Nonce().getValue();
            return new Request(
                    new AuthenticationRequest.Builder(CODE, scope, clientId, callbackUri)
                            .endpointURI(authUrl)
                            .state(new State(state))
                            .nonce(new Nonce(hashNonce(nonce)))
                            .build()
                            .toURI(),
                    Optional.of(nonce));
        }

        @Override
        public Response getOAuth2Response(String code, URI callbackUri, Optional<String> nonce)
                throws ChallengeFailedException
        {
            if (!nonce.isPresent()) {
                throw new ChallengeFailedException("Missing nonce");
            }

            OIDCTokenResponse tokenResponse = getTokenResponse(code, callbackUri, OIDCTokenResponse::parse);
            OIDCTokens tokens = tokenResponse.getOIDCTokens();
            validateTokens(tokens, nonce);
            return toResponse(tokens, Optional.empty());
        }

        @Override
        public Response refreshTokens(String refreshToken)
                throws ChallengeFailedException
        {
            OIDCTokenResponse tokenResponse = getTokenResponse(refreshToken, OIDCTokenResponse::parse);
            OIDCTokens tokens = tokenResponse.getOIDCTokens();
            validateTokens(tokens);
            return toResponse(tokens, Optional.of(refreshToken));
        }

View on GitHub (pinned to 55bb57d202)