{"record":{"id":"18f5a582a2b3b2a8","repo":"hashicorp/nomad","slug":"no-oidc-request-found-for-client-nonce","errorCode":null,"errorMessage":"no OIDC request found for client nonce","messagePattern":"no OIDC request found for client nonce","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/acl_endpoint.go","lineNumber":2789,"sourceCode":"\t// validated\n\tproviderMetadata := struct {\n\t\tAuthorizationResponseIssParameterSupported bool `json:\"authorization_response_iss_parameter_supported\"`\n\t}{}\n\tif err := oidcProvider.Claims(&providerMetadata); err != nil {\n\t\treturn fmt.Errorf(\"failed to retrieve OIDC provider metadata: %w\", err)\n\t}\n\tif providerMetadata.AuthorizationResponseIssParameterSupported {\n\t\tif args.Iss == \"\" || args.Iss != authMethod.Config.OIDCDiscoveryURL {\n\t\t\treturn errors.New(\"invalid or missing issuer parameter in callback\")\n\t\t}\n\t}\n\n\t// Retrieve the request generated in OIDCAuthURL()\n\toidcReq := a.oidcRequestCache.LoadAndDelete(args.ClientNonce) // I am so done with this NONCENSE\n\tif oidcReq == nil {\n\t\t// note: this may happen if there is a leader election between getting\n\t\t// the auth url and completing the login flow here.\n\t\treturn errors.New(\"no OIDC request found for client nonce\")\n\t}\n\n\t// Generate a context with a deadline. This is passed to the OIDC provider\n\t// and used when making remote HTTP requests.\n\tctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(aclOIDCCallbackRequestExpiryTime))\n\tdefer cancel()\n\n\t// Exchange the state and code for an OIDC provider token.\n\toidcToken, err := oidcProvider.Exchange(ctx, oidcReq, args.State, args.Code)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to exchange token with provider: %v\", err)\n\t}\n\tif !oidcToken.Valid() {\n\t\treturn errors.New(\"exchanged token is not valid; potentially expired or empty\")\n\t}\n\n\tvar idTokenClaims map[string]any\n\tif err := oidcToken.IDToken().Claims(&idTokenClaims); err != nil {","sourceCodeStart":2771,"sourceCodeEnd":2807,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/acl_endpoint.go#L2771-L2807","documentation":"OIDCCompleteAuth looks up the pending OIDC request that OIDCAuthURL stored in a server-side cache keyed by ClientNonce. If LoadAndDelete finds no entry, the login flow cannot continue and this error is returned. The cache is per-leader in-memory state, so any event that wipes it (leader failover, expiry, restart) or a mismatched nonce triggers the error.","triggerScenarios":"Calling ACL.OIDCCompleteAuth with a ClientNonce that was never issued by OIDCAuthURL, a nonce already consumed by a prior OIDCCompleteAuth call, or a nonce whose cache entry was lost when the Nomad server leader changed between OIDCAuthURL and OIDCCompleteAuth.","commonSituations":"Leader election during an interactive OIDC login; user double-submitting the callback (nonce deleted on first use); starting login against one cluster and completing against another; replaying an old callback URL after cache entry TTL expiry.","solutions":["Restart the login flow: call OIDCAuthURL again after the leader has stabilized to mint a fresh nonce, then complete auth with that new nonce.","Ensure OIDCAuthURL and OIDCCompleteAuth target the same Nomad cluster/address so the nonce lands in the same cache.","Do not reuse a callback: complete the flow exactly once per nonce and generate a new nonce on retry.","Check for frequent leader elections (server instability) if this recurs for multiple users."],"exampleFix":"// before: reuse stale nonce after leader change\nresp, err := acl.OIDCCompleteAuth(ctx, &api.ACLAuthCompleteArgs{ClientNonce: oldNonce, State: state, Code: code})\n// after: restart flow to get a fresh nonce\nauthURL, nonce, err := acl.GetOIDCAuthURL(ctx, req)\n// redirect user to authURL, then complete with the same `nonce`","handlingStrategy":"retry","validationCode":"// caller cannot inspect the server cache; validate inputs and freshness instead\nif nonce == \"\" || time.Since(nonceIssuedAt) > 10*time.Minute {\n    // nonce stale or missing: re-run OIDCAuthURL before completing\n}","typeGuard":null,"tryCatchPattern":"err := acl.OIDCCompleteAuth(ctx, args)\nif err != nil && strings.Contains(err.Error(), \"no OIDC request found for client nonce\") {\n    // restart login: fetch a fresh auth URL + nonce and retry once\n}","preventionTips":["Complete the OIDC callback immediately after obtaining the auth URL.","Never reuse a nonce or callback URL; generate a new one per login attempt.","Pin the login flow to one cluster and avoid it during known maintenance/leader elections."],"tags":["oidc","acl","nonce","session-state"],"backgroundTag":"oidc-nonce-state-missing","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}