{"record":{"id":"9364f965dd62bf53","repo":"bitwarden/server","slug":"resource-not-found-9364f9","errorCode":null,"errorMessage":"Resource not found.","messagePattern":"Resource not found\\.","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Api/Auth/Controllers/AccountsController.cs","lineNumber":652,"sourceCode":"            return;\n        }\n\n        foreach (var error in result.Errors)\n        {\n            ModelState.AddModelError(string.Empty, error.Description);\n        }\n\n        await Task.Delay(2000);\n        throw new BadRequestException(ModelState);\n    }\n\n    [HttpDelete(\"sso/{organizationId}\")]\n    public async Task DeleteSsoUser(string organizationId)\n    {\n        var userId = _userService.GetProperUserId(User);\n        if (!userId.HasValue)\n        {\n            throw new NotFoundException();\n        }\n\n        await _organizationService.DeleteSsoUserAsync(userId.Value, new Guid(organizationId));\n    }\n\n    [HttpGet(\"sso/user-identifier\")]\n    public async Task<string> GetSsoUserIdentifier()\n    {\n        var user = await _userService.GetUserByPrincipalAsync(User);\n        var token = await _userService.GenerateSignInTokenAsync(user, TokenPurposes.LinkSso);\n        var userIdentifier = $\"{user.Id},{token}\";\n        return userIdentifier;\n    }\n\n    [HttpPost(\"api-key\")]\n    public async Task<ApiKeyResponseModel> ApiKey([FromBody] SecretVerificationRequestModel model)\n    {\n        var user = await _userService.GetUserByPrincipalAsync(User);","sourceCodeStart":634,"sourceCodeEnd":670,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Auth/Controllers/AccountsController.cs#L634-L670","documentation":"Thrown as NotFoundException (HTTP 404) from DELETE /accounts/sso/{organizationId}. _userService.GetProperUserId(User) returns null because the authenticated ClaimsPrincipal does not carry a recognizable user ID claim. The controller throws new NotFoundException() which the ExceptionHandlerFilterAttribute maps to HTTP 404 with the generic message 'Resource not found.'","triggerScenarios":"An authenticated request to DELETE /accounts/sso/{organizationId} arrives with a bearer token whose claims are missing or malformed — GetProperUserId cannot extract a Guid user ID from the principal's claims.","commonSituations":"The access token expired and was silently renewed with a token that lacks the sub/nameidentifier claim. A misconfigured SSO provider omits the user identifier claim. The token was minted for a service account or machine-to-machine flow that does not include a Bitwarden user ID. The middleware pipeline is misconfigured and the principal is not populated.","solutions":["Inspect the JWT claims (specifically the 'sub' or nameidentifier claim) to confirm a valid Bitwarden user Guid is present.","Re-authenticate the user to obtain a fresh access token with complete claims.","If using SSO, verify the SSO provider's claim mapping includes the user identifier.","Check that the authentication middleware (JwtBearer or cookie) is correctly registered and executed before the controller."],"exampleFix":"// before: calling with a token missing user ID claims\nclient.DefaultRequestHeaders.Authorization = new(\"Bearer\", staleOrIncompleteToken);\nawait client.DeleteAsync($\"/accounts/sso/{orgId}\"); // 404\n\n// after: re-authenticate to get a complete token\nvar token = await authService.GetAccessTokenAsync(username, password);\nclient.DefaultRequestHeaders.Authorization = new(\"Bearer\", token);\nawait client.DeleteAsync($\"/accounts/sso/{orgId}\");","handlingStrategy":"validation","validationCode":"// Validate that the token contains a user ID claim before making the call\nvar handler = new JwtSecurityTokenHandler();\nvar jwt = handler.ReadJwtToken(accessToken);\nvar hasUserId = jwt.Claims.Any(c => c.Type == \"sub\" || c.Type == ClaimTypes.NameIdentifier);\nif (!hasUserId) {\n    // Re-authenticate before proceeding\n    accessToken = await ReauthenticateAsync();\n}","typeGuard":null,"tryCatchPattern":"try {\n    await client.DeleteAsync($\"/accounts/sso/{organizationId}\");\n} catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound) {\n    // Most likely the token lacks user ID claims — re-authenticate\n    await ReauthenticateAsync();\n    logger.LogWarning(\"SSO user deletion returned 404; token may lack user claims\");\n}","preventionTips":["Always verify the access token contains a valid user identifier claim before calling user-scoped endpoints.","Handle token refresh proactively before the token expires or loses claims.","If using SSO, confirm the IdP claim mapping includes the required user identifier."],"tags":["authentication","claims","sso","not-found","authorization"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}