{"record":{"id":"46a99380eb59564d","repo":"semaphoreui/semaphore","slug":"oidc-sign-in-failed-could-not-find-or-create-the","errorCode":null,"errorMessage":"OIDC sign-in failed: could not find or create the user account. Contact your administrator.","messagePattern":"OIDC sign-in failed: could not find or create the user account\\. Contact your administrator\\.","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"api/login.go","lineNumber":1005,"sourceCode":"\t\tredirectURL, _ := url.JoinPath(util.Config.WebHost, \"/\")\n\t\thttp.Redirect(w, r, redirectURL, http.StatusTemporaryRedirect)\n\t\treturn\n\t}\n\n\tuser, err := resolveExternalUser(helpers.Store(r), externalUserProfile{\n\t\tType:          db.IdentityTypeOidc,\n\t\tProvider:      pid,\n\t\tExternalUID:   claims.sub,\n\t\tUsername:      claims.username,\n\t\tName:          claims.name,\n\t\tEmail:         claims.email,\n\t\tEmailVerified: claims.emailVerified,\n\t\t// MatchByUsername stays false: OIDC matches by email only\n\t\t// (username matching \"creates a lot of problems\" - see old comment).\n\t})\n\tif err != nil {\n\t\tlog.Error(err.Error())\n\t\thttp.Error(w, \"OIDC sign-in failed: could not find or create the user account. Contact your administrator.\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tcreateSession(w, r, user, true)\n\n\tconfig, ok := util.Config.OidcProviders[pid]\n\tif !ok {\n\t\tlog.Error(fmt.Errorf(\"no such provider: %s\", pid))\n\t\thttp.Error(w, \"Unknown OIDC provider.\", http.StatusNotFound)\n\t\treturn\n\t}\n\n\tredirectPath := \"\"\n\tif config.ReturnViaState {\n\t\tredirectPath = stateData.Return\n\t} else {\n\t\tredirectPath = mux.Vars(r)[\"redirect_path\"]\n\t}","sourceCodeStart":987,"sourceCodeEnd":1023,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/api/login.go#L987-L1023","documentation":"oidcRedirect returns this 500 when resolveExternalUser (api/login_identity.go:43) fails to map the OIDC identity to a Semaphore user: it looks up the identity by (provider, external_uid), optionally matches by verified email under external_auth_email_matching mode (never adopting local accounts), and otherwise creates a new external user. Any DB error in those steps, or an empty sub/email claim, surfaces as this message. The real cause is only in the server log line printed just before.","triggerScenarios":"POST/GET to /api/auth/oidc/<provider>/redirect with a valid state cookie and token exchange, but resolveExternalUser errors: empty claims.sub, database failure in GetExternalIdentity/GetUserByLoginOrEmail/CreateUserWithoutPassword/CreateExternalIdentity, duplicate username on user creation, or email matching rejected (local account / already-pinned identity in 'auto' mode).","commonSituations":"IdP omits the email claim or email_verified is false while external_auth_email_matching is set; IdP changes the sub value; DB out of space or migration missing; username claim collides with an existing orphaned user from a previous rolled-back flow; matching mode changed between deployments.","solutions":["Check the server log for the exact error line logged immediately before this response — it names the failing store call.","Verify the IdP sends non-empty sub and, if relying on matching, a verified email claim.","Check config external_auth_email_matching (never/auto/...) matches intent; set it so existing external users are matched by verified email.","Ensure the database is reachable, migrations are current, and no duplicate username/identity rows exist (delete orphaned users with external=true if needed).","Test a full fresh sign-in for a brand-new user to confirm user creation + identity linking works."],"exampleFix":"// before (IdP scope missing email)\nscope: \"openid\"\n// after\nscope: \"openid email profile\"  // ensures claims.email/claims.emailVerified are populated","handlingStrategy":"validation","validationCode":"// client pre-check before starting OIDC flow\nif (!idTokenClaims.sub || (relyOnEmailMatch && (!idTokenClaims.email || !idTokenClaims.email_verified))) {\n  throw new Error(\"IdP must return sub and (for matching) a verified email claim\");\n}","typeGuard":"function hasOidcIdentityClaims(c) {\n  return typeof c === \"object\" && c !== null &&\n    typeof c.sub === \"string\" && c.sub.length > 0 &&\n    (!relyOnEmailMatch || (typeof c.email === \"string\" && c.email_verified === true));\n}","tryCatchPattern":"try {\n  await signInWithOidc(providerId);\n} catch (e) {\n  if (e.status === 500 && /could not find or create the user account/.test(e.body)) {\n    // surface admin-facing message; check server logs for the store error\n  }\n}","preventionTips":["Ensure the IdP includes openid email profile scopes so sub and verified email are present","Keep external_auth_email_matching configured deliberately and document it","Monitor server logs for resolveExternalUser errors after IdP changes","Pre-provision or pre-link users when migrating providers/sub formats"],"tags":["oidc","authentication","user-provisioning","http-500"],"backgroundTag":"authentication-required","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}