bitwarden/server · error · NotFoundException

Resource not found.

Error message

Resource not found.

What it means

NotFoundException (HTTP 404 'Resource not found.') is thrown in GET ~/organizations/{id}/two-factor when _currentContext.OrganizationAdmin(orgIdGuid) returns false. Bitwarden deliberately returns NotFound instead of Forbidden here to avoid leaking the existence of an organization to non-admin callers.

Source

Thrown at src/Api/Auth/Controllers/TwoFactorController.cs:103

    {
        var user = await _userService.GetUserByPrincipalAsync(User);
        if (user == null)
        {
            throw new UnauthorizedAccessException();
        }

        var providers = user.GetTwoFactorProviders()?.Select(
            p => new TwoFactorProviderResponseModel(p.Key, p.Value));
        return new ListResponseModel<TwoFactorProviderResponseModel>(providers);
    }

    [HttpGet("~/organizations/{id}/two-factor")]
    public async Task<ListResponseModel<TwoFactorProviderResponseModel>> GetOrganization(string id)
    {
        var orgIdGuid = new Guid(id);
        if (!await _currentContext.OrganizationAdmin(orgIdGuid))
        {
            throw new NotFoundException();
        }

        var organization = await _organizationRepository.GetByIdAsync(orgIdGuid);
        if (organization == null)
        {
            throw new NotFoundException();
        }

        var providers = organization.GetTwoFactorProviders()?.Select(
            p => new TwoFactorProviderResponseModel(p.Key, p.Value));
        return new ListResponseModel<TwoFactorProviderResponseModel>(providers);
    }

    [HttpPost("get-authenticator")]
    public async Task<TwoFactorAuthenticatorResponseModel> GetAuthenticator(
        [FromBody] SecretVerificationRequestModel model)
    {
        var user = await ValidateUserBySecretAsync(model);

View on GitHub (pinned to e93b962371)

Solutions

  1. Confirm the caller holds the OrganizationAdmin role (or Owner) for the exact organization id in the path.
  2. Verify the organization id guid is correct and the user is still an active member of that org.
  3. If a custom role is in use, ensure it grants the two-factor/policy management permission.
  4. Authenticate as an organization admin and retry.

Example fix

// before: calling as a standard org user
api.get(`/organizations/${orgId}/two-factor`)
// after: authenticate with an admin principal
api.setAuth(adminTokenForOrg(orgId));
api.get(`/organizations/${orgId}/two-factor`);
Defensive patterns

Strategy: validation

Validate before calling

const isAdmin = await orgService.isOrgAdmin(orgId);
if (!isAdmin) throw new ForbiddenError('Caller is not an org admin');

Try / catch

try { await api.get(`/organizations/${orgId}/two-factor`); }
catch (e) {
  if (e.response?.status === 404) { throw new NotFoundOrForbiddenError('Not an admin or org missing'); }
  throw e;
}

Prevention

When it happens

Trigger: GET /api/organizations/{id}/two-factor (TwoFactorController.GetOrganization at line 103) called by a user who is not an organization admin for that org, or whose membership/permissions do not grant the admin claim for orgIdGuid.

Common situations: The caller is a regular org user or custom-role without admin rights, the org id in the URL is mistyped/copied wrong, or the user's org membership was downgraded/removed. The 404 masks a 403 by design.

Related errors


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