{"record":{"id":"8bed5378bc5544d8","repo":"bitwarden/server","slug":"unauthorized-8bed53","errorCode":null,"errorMessage":"Unauthorized.","messagePattern":"Unauthorized\\.","errorType":"http","errorClass":"UnauthorizedAccessException","httpStatus":401,"severity":"error","filePath":"src/Api/Auth/Controllers/TwoFactorController.cs","lineNumber":89,"sourceCode":"        _authRequestRepository = authRequestRepository;\n        _duoUniversalTokenService = duoUniversalConfigService;\n        _twoFactorAuthenticatorDataProtector = twoFactorAuthenticatorDataProtector;\n        _twoFactorUserVerificationDataProtector = twoFactorUserVerificationDataProtector;\n        _twoFactorUserVerificationTokenableFactory = twoFactorUserVerificationTokenableFactory;\n        _ssoEmailTwoFactorSessionDataProtector = ssoEmailTwoFactorSessionDataProtector;\n        _twoFactorEmailService = twoFactorEmailService;\n        _startTwoFactorWebAuthnRegistrationCommand = startTwoFactorWebAuthnRegistrationCommand;\n        _completeTwoFactorWebAuthnRegistrationCommand = completeTwoFactorWebAuthnRegistrationCommand;\n        _deleteTwoFactorWebAuthnCredentialCommand = deleteTwoFactorWebAuthnCredentialCommand;\n    }\n\n    [HttpGet(\"\")]\n    public async Task<ListResponseModel<TwoFactorProviderResponseModel>> Get()\n    {\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)","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Auth/Controllers/TwoFactorController.cs#L71-L107","documentation":"UnauthorizedAccessException is thrown (which the Bitwarden pipeline maps to HTTP 401 'Unauthorized.') when _userService.GetUserByPrincipalAsync(User) returns null in the GET /two-factor endpoint. This means the authenticated principal could not be resolved to a real User entity, typically because the token is absent, expired, revoked, or the user record no longer exists.","triggerScenarios":"GET /api/users/two-factor (TwoFactorController.Get at line 89) called with a missing/expired access token, a revoked session, or a principal whose user was deleted. The explicit null-check guard fires before any provider data is loaded.","commonSituations":"Client stored a stale access token after logout/session-expiry, the auth cookie expired, or the account was deleted between token issuance and this call. Also occurs in tests/mocks where the user principal is not seeded.","solutions":["Refresh or re-supply a valid access token (re-login) before calling the two-factor list endpoint.","Ensure the request includes the Authorization: Bearer <token> header with a non-expired token.","If the user record was deleted, no token will work; recreate or restore the account.","In integration tests, seed an authenticated user principal via the test SutProvider/auth fixtures."],"exampleFix":"// before\nconst res = await api.get('/users/two-factor'); // stale token\n// after\nawait authService.refreshToken();\nconst res = await api.get('/users/two-factor', { headers: authHeader() });","handlingStrategy":"validation","validationCode":"if (!authService.hasValidToken()) { await authService.refreshOrReLogin(); }","typeGuard":null,"tryCatchPattern":"try { return await api.get('/users/two-factor'); }\ncatch (e) {\n  if (e.response?.status === 401) { await authService.reauthenticate(); throw e; }\n  throw e;\n}","preventionTips":["Refresh tokens proactively before expiry.","Handle 401 globally in an axios/fetch interceptor to trigger re-login.","Do not assume a long-cached token is still valid."],"tags":["auth","unauthorized","two-factor","principal"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}