{"record":{"id":"def12e8694206d2f","repo":"fatedier/frp","slug":"received-different-oidc-subject-in-login-and-ping","errorCode":null,"errorMessage":"received different OIDC subject in login and ping. new subject: %s","messagePattern":"received different OIDC subject in login and ping\\. new subject: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/oidc.go","lineNumber":318,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid OIDC token in login: %v\", err)\n\t}\n\tauth.mu.Lock()\n\tauth.subjectsFromLogin[token.Subject] = struct{}{}\n\tauth.mu.Unlock()\n\treturn nil\n}\n\nfunc (auth *OidcAuthConsumer) verifyPostLoginToken(privilegeKey string) (err error) {\n\ttoken, err := auth.verifier.Verify(context.Background(), privilegeKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid OIDC token in ping: %v\", err)\n\t}\n\tauth.mu.RLock()\n\t_, ok := auth.subjectsFromLogin[token.Subject]\n\tauth.mu.RUnlock()\n\tif !ok {\n\t\treturn fmt.Errorf(\"received different OIDC subject in login and ping. \"+\n\t\t\t\"new subject: %s\",\n\t\t\ttoken.Subject)\n\t}\n\treturn nil\n}\n\nfunc (auth *OidcAuthConsumer) VerifyPing(pingMsg *msg.Ping) (err error) {\n\tif !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {\n\t\treturn nil\n\t}\n\n\treturn auth.verifyPostLoginToken(pingMsg.PrivilegeKey)\n}\n\nfunc (auth *OidcAuthConsumer) VerifyNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (err error) {\n\tif !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeNewWorkConns) {\n\t\treturn nil\n\t}","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/auth/oidc.go#L300-L336","documentation":"Anti-spoofing check on the frps side: after a ping's JWT verifies successfully, verifyPostLoginToken looks up the token's Subject claim in the set of subjects recorded during VerifyLogin. If the ping token's subject is not among them, frps concludes a different identity is now signing pings for a session established by another identity, and rejects it.","triggerScenarios":"HeartBeats auth scope enabled, and the JWT attached to Ping resolves to a subject different from any subject seen in the Login message — e.g. frpc switched client credentials mid-session, the IdP merged/renamed the user, or one process reused a session with another principal's token.","commonSituations":"Rotating oidc.clientid/clientsecret (different service account) while a connection is alive; a load balancer putting pings from a second frpc instance onto the frps session of the first; tokens minted by a different realm after an issuer migration.","solutions":["Restart the frpc connection after changing OIDC credentials so Login and Ping are signed by the same identity","Ensure exactly one frpc instance (one identity) uses a given frps session — do not share runIDs across instances","Confirm the IdP issues a stable sub claim for the same client across refreshes","If the migration to a new subject was intentional, re-login instead of reusing the existing session"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before sending ping: ensure same subject as the login token\nloginSub := subjectOf(loginToken)\npingSub := subjectOf(pingToken)\nif loginSub != pingSub {\n    return errors.New(\"ping token subject differs from login; re-login required\")\n}","typeGuard":null,"tryCatchPattern":"if err := consumer.VerifyPing(pingMsg); err != nil && strings.Contains(err.Error(), \"different OIDC subject\") {\n    terminateSession() // identity change mid-session is unrecoverable; force fresh login\n}","preventionTips":["Never change OIDC client credentials on a live frpc; restart instead","One frpc identity per frps session","Verify IdP issues stable sub claims across token refreshes"],"tags":["frp","oidc","subject-mismatch","session","anti-spoofing"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}