{"record":{"id":"14af6def86281a5b","repo":"prestodb/presto","slug":"missing-nonce","errorCode":null,"errorMessage":"Missing nonce","messagePattern":"Missing nonce","errorType":"http","errorClass":"ChallengeFailedException","httpStatus":401,"severity":"error","filePath":"presto-main/src/main/java/com/facebook/presto/server/security/oauth2/NimbusOAuth2Client.java","lineNumber":342,"sourceCode":"        public Request createAuthorizationRequest(String state, URI callbackUri)\n        {\n            String nonce = new Nonce().getValue();\n            return new Request(\n                    new AuthenticationRequest.Builder(CODE, scope, clientId, callbackUri)\n                            .endpointURI(authUrl)\n                            .state(new State(state))\n                            .nonce(new Nonce(hashNonce(nonce)))\n                            .build()\n                            .toURI(),\n                    Optional.of(nonce));\n        }\n\n        @Override\n        public Response getOAuth2Response(String code, URI callbackUri, Optional<String> nonce)\n                throws ChallengeFailedException\n        {\n            if (!nonce.isPresent()) {\n                throw new ChallengeFailedException(\"Missing nonce\");\n            }\n\n            OIDCTokenResponse tokenResponse = getTokenResponse(code, callbackUri, OIDCTokenResponse::parse);\n            OIDCTokens tokens = tokenResponse.getOIDCTokens();\n            validateTokens(tokens, nonce);\n            return toResponse(tokens, Optional.empty());\n        }\n\n        @Override\n        public Response refreshTokens(String refreshToken)\n                throws ChallengeFailedException\n        {\n            OIDCTokenResponse tokenResponse = getTokenResponse(refreshToken, OIDCTokenResponse::parse);\n            OIDCTokens tokens = tokenResponse.getOIDCTokens();\n            validateTokens(tokens);\n            return toResponse(tokens, Optional.of(refreshToken));\n        }\n","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main/src/main/java/com/facebook/presto/server/security/oauth2/NimbusOAuth2Client.java#L324-L360","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the challenge step (startChallenge) stores the nonce and the callback passes it back via getOAuth2Response(code, callbackUri, Optional.of(nonce))","Use sticky sessions / shared state store when running multiple coordinators behind a load balancer","Clear stale oauth2 state cookies and retry the login flow in a single browser tab","Check that the HttpServer authentication config consistently uses the OIDC (nonce) path"],"exampleFix":"// before\nclient.getOAuth2Response(code, callbackUri, Optional.empty());\n// after\nclient.getOAuth2Response(code, callbackUri, Optional.of(savedNonce)); // nonce captured at challenge time","handlingStrategy":"validation","validationCode":"if (nonce == null || nonce.isEmpty()) { throw new IllegalStateException(\"OAuth2 challenge state missing nonce; restart login flow\"); }","typeGuard":"boolean hasNonce(java.util.Optional<String> nonce) { return nonce != null && nonce.isPresent() && !nonce.get().isEmpty(); }","tryCatchPattern":"try { return client.getOAuth2Response(code, callbackUri, nonce); } catch (ChallengeFailedException e) { restartAuthenticationChallenge(); throw e; }","preventionTips":["Store the nonce at challenge time and pass it through the callback reliably","Use sticky sessions or a shared state store for multi-node deployments","Ask users to retry login in a single tab; avoid refreshing old callback URLs"],"tags":["oauth2","oidc","authentication"],"backgroundTag":"missing-oauth2-nonce","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}