{"record":{"id":"d28ca863c9b4b4d7","repo":"goharbor/harbor","slug":"state-mismatch","errorCode":null,"errorMessage":"State mismatch","messagePattern":"State mismatch","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"src/core/controllers/oidc.go","lineNumber":113,"sourceCode":"\t\treturn\n\t}\n\tif err := oc.SetSession(stateKey, state); err != nil {\n\t\tlog.Errorf(\"failed to set session for key: %s, error: %v\", stateKey, err)\n\t\toc.SendInternalServerError(err)\n\t\treturn\n\t}\n\tlog.Debugf(\"State dumped to session: %s\", state)\n\t// Force to use the func 'Redirect' of beego.Controller\n\toc.Controller.Redirect(url, http.StatusFound)\n}\n\n// Callback handles redirection from OIDC provider.  It will exchange the token and\n// kick off onboard if needed.\nfunc (oc *OIDCController) Callback() {\n\tif oc.Ctx.Request.URL.Query().Get(\"state\") != oc.GetSession(stateKey) {\n\t\tlog.Errorf(\"State mismatch, in session: %s, in url: %s\", oc.GetSession(stateKey),\n\t\t\toc.Ctx.Request.URL.Query().Get(\"state\"))\n\t\toc.SendBadRequestError(errors.New(\"State mismatch\"))\n\t\treturn\n\t}\n\terrorCode := oc.Ctx.Request.URL.Query().Get(\"error\")\n\tif errorCode != \"\" {\n\t\terrorDescription := oc.Ctx.Request.URL.Query().Get(\"error_description\")\n\t\tlog.Errorf(\"OIDC callback returned error: %s - %s\", errorCode, errorDescription)\n\t\toc.SendBadRequestError(errors.Errorf(\"OIDC callback returned error: %s - %s\", errorCode, errorDescription))\n\t\treturn\n\t}\n\tvar redirectURLStr string\n\tredirectURL := oc.GetSession(redirectURLKey)\n\tif redirectURL != nil {\n\t\tredirectURLStr = redirectURL.(string)\n\t\tif err := oc.DelSession(redirectURLKey); err != nil {\n\t\t\tlog.Errorf(\"failed to delete session for key:%s, error: %v\", redirectURLKey, err)\n\t\t\toc.SendInternalServerError(err)\n\t\t\treturn\n\t\t}","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/core/controllers/oidc.go#L95-L131","documentation":"OIDC Callback answers HTTP 400 'State mismatch' when the state query parameter returned by the OIDC provider differs from the state stored in the user's Harbor session. This is the CSRF check of the authorization-code flow: the callback must land in the same browser session that initiated login.","triggerScenarios":"GET /c/oidc/callback when the Harbor session cookie was not sent (blocked, incognito, new browser), the flow was started in a different browser, an old callback URL is replayed, or the session lives in another core replica.","commonSituations":"Core replicas behind a load balancer without sticky sessions (session affinity); SameSite/Secure cookie settings blocking the session cookie; clock- or expiry-related session loss; user copying the callback URL into another tab.","solutions":["Restart the login from the Harbor sign-on page and finish it in the same browser","Enable session affinity (or a shared session store) between core replicas","Check the browser accepts Harbor's session cookie (domain, Secure, SameSite)","Verify the OIDC redirect URI registered at the provider exactly matches Harbor's callback URL"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Client-side: verify the browser still holds the Harbor session before redirecting to the IdP\nif !harborSessionCookiePresent(document) { /* clear login state and start fresh */ }","typeGuard":"func isStateMismatch(resp *http.Response) bool {\n    return resp.StatusCode == http.StatusBadRequest && strings.Contains(readBody(resp), \"State mismatch\")\n}","tryCatchPattern":"// OIDC client middleware: on state mismatch, restart the flow once\nif isStateMismatch(resp) {\n    resp = restartLoginFlow() // new state, new nonce, same session cookie\n}","preventionTips":["Complete OIDC login in one browser session; never re-use callback URLs","Enable sticky sessions or shared session storage for core replicas","Keep session cookie attributes (Secure, SameSite) compatible with the SSO redirect chain"],"tags":["harbor","oidc","sso","session","csrf"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}