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
- Confirm the caller holds the OrganizationAdmin role (or Owner) for the exact organization id in the path.
- Verify the organization id guid is correct and the user is still an active member of that org.
- If a custom role is in use, ensure it grants the two-factor/policy management permission.
- 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
- Check org admin status client-side before calling org-scoped endpoints.
- Remember Bitwarden returns 404 (not 403) for permission failures on org endpoints.
- Keep the org id constant; avoid manual guid entry.
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
- Resource not found.
- Resource not found.
- Organization not found.
- Free Bitwarden Families sponsorship has been disabled by you
- Can only redeem sponsorship for an organization you own.
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/fb4af1a83f0a3759.
Report an issue: GitHub.