{"record":{"id":"fb4af1a83f0a3759","repo":"bitwarden/server","slug":"resource-not-found-fb4af1","errorCode":null,"errorMessage":"Resource not found.","messagePattern":"Resource not found\\.","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Api/Auth/Controllers/TwoFactorController.cs","lineNumber":103,"sourceCode":"    {\n        var user = await _userService.GetUserByPrincipalAsync(User);\n        if (user == null)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var providers = user.GetTwoFactorProviders()?.Select(\n            p => new TwoFactorProviderResponseModel(p.Key, p.Value));\n        return new ListResponseModel<TwoFactorProviderResponseModel>(providers);\n    }\n\n    [HttpGet(\"~/organizations/{id}/two-factor\")]\n    public async Task<ListResponseModel<TwoFactorProviderResponseModel>> GetOrganization(string id)\n    {\n        var orgIdGuid = new Guid(id);\n        if (!await _currentContext.OrganizationAdmin(orgIdGuid))\n        {\n            throw new NotFoundException();\n        }\n\n        var organization = await _organizationRepository.GetByIdAsync(orgIdGuid);\n        if (organization == null)\n        {\n            throw new NotFoundException();\n        }\n\n        var providers = organization.GetTwoFactorProviders()?.Select(\n            p => new TwoFactorProviderResponseModel(p.Key, p.Value));\n        return new ListResponseModel<TwoFactorProviderResponseModel>(providers);\n    }\n\n    [HttpPost(\"get-authenticator\")]\n    public async Task<TwoFactorAuthenticatorResponseModel> GetAuthenticator(\n        [FromBody] SecretVerificationRequestModel model)\n    {\n        var user = await ValidateUserBySecretAsync(model);","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Auth/Controllers/TwoFactorController.cs#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: calling as a standard org user\napi.get(`/organizations/${orgId}/two-factor`)\n// after: authenticate with an admin principal\napi.setAuth(adminTokenForOrg(orgId));\napi.get(`/organizations/${orgId}/two-factor`);","handlingStrategy":"validation","validationCode":"const isAdmin = await orgService.isOrgAdmin(orgId);\nif (!isAdmin) throw new ForbiddenError('Caller is not an org admin');","typeGuard":null,"tryCatchPattern":"try { await api.get(`/organizations/${orgId}/two-factor`); }\ncatch (e) {\n  if (e.response?.status === 404) { throw new NotFoundOrForbiddenError('Not an admin or org missing'); }\n  throw e;\n}","preventionTips":["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."],"tags":["two-factor","authorization","organization","not-found"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}