{"record":{"id":"688a31a57311e98b","repo":"bitwarden/server","slug":"user-verification-failed-688a31","errorCode":null,"errorMessage":"User verification failed.","messagePattern":"User verification failed\\.","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/Auth/Controllers/AccountsController.cs","lineNumber":679,"sourceCode":"        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);\n        if (user == null)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        if (!await _userService.VerifySecretAsync(user, model.Secret))\n        {\n            await Task.Delay(2000);\n            throw new BadRequestException(string.Empty, \"User verification failed.\");\n        }\n\n        return new ApiKeyResponseModel(user);\n    }\n\n    [HttpPost(\"rotate-api-key\")]\n    public async Task<ApiKeyResponseModel> RotateApiKey([FromBody] SecretVerificationRequestModel model)\n    {\n        var user = await _userService.GetUserByPrincipalAsync(User);\n        if (user == null)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        if (!await _userService.VerifySecretAsync(user, model.Secret))\n        {\n            await Task.Delay(2000);\n            throw new BadRequestException(string.Empty, \"User verification failed.\");","sourceCodeStart":661,"sourceCodeEnd":697,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Auth/Controllers/AccountsController.cs#L661-L697","documentation":"Thrown as BadRequestException(string.Empty, \"User verification failed.\") (HTTP 400) from POST /accounts/api-key. _userService.VerifySecretAsync(user, model.Secret) returns false — the provided master password hash does not match the stored value. A 2-second Task.Delay precedes the throw as a timing-attack mitigation to make brute-force enumeration slower.","triggerScenarios":"POST /accounts/api-key is called with a SecretVerificationRequestModel whose Secret field (the master password hash) is incorrect. The user exists and is authenticated, but the secret verification fails.","commonSituations":"User recently changed their master password but the client is still sending the old hash. The client-side PBKDF2/argon2 iteration count or algorithm was updated but the client hasn't been refreshed. The user mistyped their master password. A different hashing implementation on the client produces a hash that doesn't match the server's stored value.","solutions":["Prompt the user to re-enter their master password and resend the request.","Verify the client's password hashing parameters (iteration count, algorithm, salt) match what the server expects — check the identity token's Kdf parameters.","If the user recently changed their master password, ensure the client has updated its locally cached hash.","Check for client version mismatches where the hashing algorithm (PBKDF2 vs Argon2id) or iteration count differs from server expectations."],"exampleFix":"// before: sending a stale or incorrect password hash\nvar resp = await client.PostAsJsonAsync(\"/accounts/api-key\",\n    new SecretVerificationRequestModel { Secret = oldMasterPasswordHash });\n// 400: User verification failed.\n\n// after: re-derive hash from freshly entered password using correct params\nvar hash = Crypto.HashPassword(promptedPassword, kdfParams);\nvar resp = await client.PostAsJsonAsync(\"/accounts/api-key\",\n    new SecretVerificationRequestModel { Secret = hash });","handlingStrategy":"validation","validationCode":"// Verify the master password hash is correctly derived before sending\nvar prelogin = await GetPreloginInfoAsync(email);\nvar derivedHash = PBKDF2.Sha256(masterPassword, prelogin.Email, prelogin.Iterations);\n\n// Optionally: validate the hash length/format matches expectations\nif (derivedHash.Length != expectedHashLength) {\n    return Error(\"Password hash derivation produced an unexpected result\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    var resp = await client.PostAsJsonAsync(\"/accounts/api-key\",\n        new SecretVerificationRequestModel { Secret = derivedHash });\n    resp.EnsureSuccessStatusCode();\n} catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.BadRequest) {\n    // Secret verification failed — prompt user to re-enter master password\n    ShowUserError(\"Master password verification failed. Please re-enter your master password.\");\n}","preventionTips":["Always derive the master password hash using the KDF parameters returned by the server's prelogin response.","Prompt the user to re-enter their password rather than retrying with the same hash after a failure.","Keep the client's crypto library version in sync with the server's expectations."],"tags":["master-password","secret-verification","api-key","bad-request","brute-force-protection"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}