bitwarden/server · error · Exception

OrganizationOrSsoConfigNotFound

Error message

OrganizationOrSsoConfigNotFound

What it means

Thrown in AccountController.FindUserFromExternalProviderAsync (line 455) when the SsoConfig for the organization is null or its Enabled property is false. This is checked after resolving the orgId from the external auth scheme and looking up _ssoConfigRepository.GetByOrganizationIdAsync.

Source

Thrown at bitwarden_license/src/Sso/Controllers/AccountController.cs:455

    /// The claims on the external identity are used to determine an `externalId`, and that is used to find the appropriate `SsoUser` and `User` records.
    /// </summary>
    private async Task<(
        User? possibleSsoUser,
        string provider,
        string providerUserId,
        IEnumerable<Claim> claims,
        SsoConfigurationData config
    )> FindUserFromExternalProviderAsync(AuthenticateResult result)
    {
        // FIXME: Update this file to be null safe and then delete the line below
#nullable disable
        var provider = result.Properties.Items["scheme"];
        //Todo: Validate provider is a valid GUID with TryParse instead. When this is invalid it throws an exception
        var orgId = new Guid(provider);
        var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(orgId);
        if (ssoConfig == null || !ssoConfig.Enabled)
        {
            throw new Exception(_i18nService.T("OrganizationOrSsoConfigNotFound"));
        }

        var ssoConfigData = ssoConfig.GetData();
        var externalUser = result.Principal;

        // Validate acr claim against expectation before going further
        if (!string.IsNullOrWhiteSpace(ssoConfigData.ExpectedReturnAcrValue))
        {
            var acrClaim = externalUser.FindFirst(JwtClaimTypes.AuthenticationContextClassReference);
            if (acrClaim?.Value != ssoConfigData.ExpectedReturnAcrValue)
            {
                throw new Exception(_i18nService.T("AcrMissingOrInvalid"));
            }
        }

        // Ensure the NameIdentifier used is not a transient name ID, if so, we need a different attribute
        //  for the user identifier.
        static bool nameIdIsNotTransient(Claim c) => c.Type == ClaimTypes.NameIdentifier

View on GitHub (pinned to e93b962371)

Solutions

  1. Verify SSO is enabled for the organization in the admin portal (SsoConfig.Enabled = true).
  2. Confirm the organization ID in the auth scheme matches the org with the SSO config.
  3. If SSO was intentionally disabled, inform users and use master password login instead.
Defensive patterns

Strategy: validation

Validate before calling

// Verify SSO config is enabled before starting the flow
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(orgId);
if (ssoConfig == null || !ssoConfig.Enabled)
    return BadRequest("SSO is not enabled for this organization.");

Try / catch

try { await FindUserFromExternalProviderAsync(result); }
catch (Exception ex) when (ex.Message.Contains("OrganizationOrSsoConfigNotFound"))
{ /* inform user SSO is not configured; fall back to password */ }

Prevention

When it happens

Trigger: The external callback fires for an organization that has no SsoConfig record, or whose SsoConfig.Enabled is false (SSO was disabled by an admin after the flow started).

Common situations: Admin disabled or deleted the SSO configuration while a login was in progress; organization was created without SSO setup; SsoConfig was soft-deleted; the wrong organization ID is being used due to a stale scheme.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/a7c1876c309ef80b. Report an issue: GitHub.