{"record":{"id":"6c3e9bc64d6d4be3","repo":"ory/hydra","slug":"flow-subject-s-does-not-match-the-handledloginreq","errorCode":null,"errorMessage":"flow Subject %s does not match the HandledLoginRequest Subject %s","messagePattern":"flow Subject (.+?) does not match the HandledLoginRequest Subject (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"flow/flow.go","lineNumber":310,"sourceCode":"}\n\n// InvalidateDeviceRequest shifts the flow state to DeviceFlowStateUsed. This\n// transition is executed upon device completion.\nfunc (f *Flow) InvalidateDeviceRequest() error {\n\tif err := f.State.IsAny(DeviceFlowStateUnused); err != nil {\n\t\treturn err\n\t}\n\tf.State = DeviceFlowStateUsed\n\treturn nil\n}\n\nfunc (f *Flow) HandleLoginRequest(h *HandledLoginRequest) error {\n\tif err := f.State.IsAny(FlowStateLoginInitialized, FlowStateLoginUnused, FlowStateLoginError); err != nil {\n\t\treturn err\n\t}\n\n\tif f.Subject != \"\" && h.Subject != \"\" && f.Subject != h.Subject {\n\t\treturn errors.Errorf(\"flow Subject %s does not match the HandledLoginRequest Subject %s\", f.Subject, h.Subject)\n\t}\n\n\tif f.ForceSubjectIdentifier != \"\" && h.ForceSubjectIdentifier != \"\" && f.ForceSubjectIdentifier != h.ForceSubjectIdentifier {\n\t\treturn errors.Errorf(\"flow ForceSubjectIdentifier %s does not match the HandledLoginRequest ForceSubjectIdentifier %s\", f.ForceSubjectIdentifier, h.ForceSubjectIdentifier)\n\t}\n\n\tf.State = FlowStateLoginUnused\n\n\tif f.Context != nil {\n\t\tf.Context = h.Context\n\t}\n\n\tf.Subject = h.Subject\n\tf.ForceSubjectIdentifier = h.ForceSubjectIdentifier\n\n\tf.IdentityProviderSessionID = sqlxx.NullString(h.IdentityProviderSessionID)\n\tf.LoginRemember = h.Remember\n\tf.LoginRememberFor = h.RememberFor","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/flow/flow.go#L292-L328","documentation":"Flow.HandleLoginRequest rejects a HandledLoginRequest whose Subject differs from the Subject already stored on the Flow. Hydra flows pin the authenticated user at login initialization; accepting a different subject later would let the same flow be reused to impersonate another user, so the mismatch is treated as a hard error.","triggerScenarios":"Calling Flow.HandleLoginRequest (public) when both f.Subject and h.Subject are non-empty and unequal — e.g. the login flow was initialized/claimed for user A but the LoginRequestHandler resolved user B, or the flow was fetched twice and completed with a different login session.","commonSituations":"Reusing a stale login challenge after the user logged out and in as a different account; cookie/session swapping between flow creation and login acceptance; multiple browser tabs completing the same flow with different identities; replaying a saved HandledLoginRequest object from a previous authentication.","solutions":["Ensure the subject that accepted the login equals the flow's stored Subject before calling HandleLoginRequest; abort and re-initialize the flow if the user changed","Fetch the flow fresh from storage and re-run the login provider so the HandledLoginRequest reflects the current authenticated subject","If the user genuinely changed, create a new login flow (new challenge) instead of reusing the old one","Check that you are not passing a HandledLoginRequest belonging to another flow (mixed-up objects/keys)"],"exampleFix":"// before\nhandled := &flow.HandledLoginRequest{Subject: currentUser.Subject, Context: ...}\nerr := loginFlow.HandleLoginRequest(handled) // panics/errors if subject differs\n// after\nif loginFlow.Subject != \"\" && currentUser.Subject != loginFlow.Subject {\n    loginFlow, err = newLoginFlowFor(currentUser) // create a fresh flow\n    if err != nil { return err }\n}\nerr := loginFlow.HandleLoginRequest(handled)","handlingStrategy":"validation","validationCode":"if loginFlow.Subject != \"\" && handled.Subject != \"\" && loginFlow.Subject != handled.Subject {\n    return fmt.Errorf(\"flow subject %s != handled subject %s; re-initialize login flow\", loginFlow.Subject, handled.Subject)\n}\nerr := loginFlow.HandleLoginRequest(handled)","typeGuard":null,"tryCatchPattern":"if err := flow.HandleLoginRequest(handled); err != nil {\n    if strings.Contains(err.Error(), \"does not match the HandledLoginRequest Subject\") {\n        flow, err = reinitializeLoginFlow(authRequest)\n    }\n    return err\n}","preventionTips":["Always fetch the flow fresh from storage immediately before calling HandleLoginRequest","Re-run your login provider on every request instead of caching a completed HandledLoginRequest across sessions","Reject a login (error prompt) when the authenticated subject differs from the flow's subject","Key flows by challenge ID and never share HandledLoginRequest objects between flows"],"tags":["oauth2","oidc","hydra","login-flow","subject-mismatch"],"backgroundTag":"login-subject-mismatch","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}