{"record":{"id":"57f47bef598145f2","repo":"bitwarden/server","slug":"ssoorgmembershiprequired","errorCode":"ssoOrgMembershipRequired","errorMessage":"Org membership required before SSO for org '{organizationDisplayName}'.","messagePattern":"Org membership required before SSO for org '(.+?)'\\.","errorType":"exception","errorClass":"SsoAuthnRequiresOrgMembershipException","httpStatus":null,"severity":"error","filePath":"bitwarden_license/src/Sso/Controllers/AccountController.cs","lineNumber":571,"sourceCode":"        var organization = await GetOrganizationByProviderAsync(provider);\n\n        // Try to find an org user (null org user possible and valid here)\n        var possibleOrgUser = await GetOrganizationUserByUserAndOrgIdOrEmailAsync(possibleExistingUser, organization.Id, email);\n\n        //----------------------------------------------------\n        // Scenario 1: We've found the user in the User table\n        //----------------------------------------------------\n        if (possibleExistingUser != null)\n        {\n            User guaranteedExistingUser = possibleExistingUser;\n\n            if (guaranteedExistingUser.UsesKeyConnector &&\n                (possibleOrgUser == null || possibleOrgUser.Status == OrganizationUserStatusType.Invited))\n            {\n                throw new Exception(_i18nService.T(\"UserAlreadyExistsKeyConnector\"));\n            }\n\n            OrganizationUser guaranteedOrgUser = possibleOrgUser ?? throw new SsoAuthnRequiresOrgMembershipException(\n                organization.Id,\n                organization.DisplayName(),\n                guaranteedExistingUser.Email);\n\n            /*\n             * ----------------------------------------------------\n             *              Critical Code Check Here\n             *\n             * We want to ensure a user is not in the invited state\n             * explicitly. Users in the invited state cannot complete\n             * SSO authentication. Instead of failing with a server\n             * error page, we throw a typed exception so the SSO\n             * callback can redirect the user back to the web client's\n             * /login with a toast prompting them to sign in with their\n             * master password and accept the invite first.\n             *\n             * The security-critical property is unchanged: no SsoUser\n             * row is written and no auth session is established for","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/bitwarden_license/src/Sso/Controllers/AccountController.cs#L553-L589","documentation":"Thrown as SsoAuthnRequiresOrgMembershipException in AccountController.CreateUserAndOrgUserConditionallyAsync (line 571) when an existing user is found in the User table but has no OrganizationUser record for this organization (possibleOrgUser is null). The exception carries OrganizationId, OrganizationDisplayName, and UserEmail so the callback can redirect to the login page with an OrgMembershipRequired error code. Unlike a generic Exception, this typed exception is caught in ExternalCallback and produces a user-facing redirect instead of a 500.","triggerScenarios":"A user exists in Bitwarden and authenticates via SSO, but has no OrganizationUser row linking them to the SSO-enabling organization.","commonSituations":"User was removed from the org by an admin; user's email changed and the org membership lookup by email no longer matches; JIT provisioning is disabled and the user was never invited; org membership was revoked.","solutions":["Have an org admin invite the user to the organization, then have the user accept the invite before retrying SSO.","If JIT provisioning should auto-create the membership, verify the user is not already in the User table (JIT creates new users, not memberships for existing users).","Verify the user's email in the User table matches the email used for org membership lookup."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Already handled in ExternalCallback — the typed exception is caught and redirected:\ncatch (SsoAuthnRequiresOrgMembershipException ex)\n{\n    await HttpContext.SignOutAsync(AuthenticationSchemes.BitwardenExternalCookieAuthenticationScheme);\n    var redirectUrl = SsoRedirectUrlBuilder.BuildLoginRedirectUrl(\n        _globalSettings.BaseServiceUri.VaultWithHash,\n        ex.UserEmail, ex.OrganizationId, ex.OrganizationDisplayName,\n        SsoRedirectUrlBuilder.ErrorCodes.OrgMembershipRequired);\n    return Redirect(redirectUrl);\n}","preventionTips":["Ensure users are invited and confirmed in the org before they attempt SSO.","Keep org membership in sync when users join or leave the IdP.","The redirect URL carries the OrgMembershipRequired code — the web client should show a clear message."],"tags":["sso","authentication","organization","membership","key-connector","provisioning"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}