{"record":{"id":"8fc4e41435288ba2","repo":"hashicorp/nomad","slug":"exchanged-token-is-not-valid-potentially-expired","errorCode":null,"errorMessage":"exchanged token is not valid; potentially expired or empty","messagePattern":"exchanged token is not valid; potentially expired or empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/acl_endpoint.go","lineNumber":2803,"sourceCode":"\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 {\n\t\treturn fmt.Errorf(\"failed to retrieve the ID token claims: %v\", err)\n\t}\n\n\tvar userClaims map[string]any\n\tif !authMethod.Config.OIDCDisableUserInfo {\n\t\tif userTokenSource := oidcToken.StaticTokenSource(); userTokenSource != nil {\n\t\t\tif err := oidcProvider.UserInfo(ctx, userTokenSource, idTokenClaims[\"sub\"].(string), &userClaims); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to retrieve the user info claims: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Generate the data used by the go-bexpr selector that is an internal\n\t// representation of the claims that can be understood by Nomad.","sourceCodeStart":2785,"sourceCodeEnd":2821,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/acl_endpoint.go#L2785-L2821","documentation":"After exchanging the OIDC state and authorization code with the provider via oidcProvider.Exchange, Nomad validates the returned token with oidcToken.Valid(). If the token is invalid — expired, empty, or missing required fields — this error is returned and login fails.","triggerScenarios":"OIDCCompleteAuth where the provider returns an empty/expired token, the provider clock is skewed relative to the Nomad server, or the auth code was delayed so long the resulting token expired before validation.","commonSituations":"User sitting on the provider's login page long enough for the code/token to expire; misconfigured provider issuing tokens with no expiry or empty ID token; clock skew on the Nomad server making a fresh token look expired; provider outage returning malformed token responses.","solutions":["Retry the login promptly: complete the OIDC callback without long delays between authentication and OIDCCompleteAuth.","Verify the OIDC provider is configured correctly and issuing valid ID tokens (test with the provider's own debugging/token endpoint).","Synchronize clocks on Nomad servers and the provider (NTP) to eliminate skew-based invalidity.","Check provider logs for errors at exchange time; fix client secret/redirect URIs if exchange returns degraded tokens."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if code == \"\" || state == \"\" {\n    return errors.New(\"missing state/code from provider callback; restart login\")\n}","typeGuard":null,"tryCatchPattern":"_, err := acl.OIDCCompleteAuth(ctx, args)\nif err != nil && strings.Contains(err.Error(), \"exchanged token is not valid\") {\n    // token expired/invalid: restart the OIDC login from scratch promptly\n}","preventionTips":["Finish the login flow quickly; don't let the auth code sit unused.","Keep server clocks NTP-synchronized.","Validate the OIDC provider configuration in a staging environment before production."],"tags":["oidc","token","expiry","acl"],"backgroundTag":"oidc-token-invalid","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"}