{"record":{"id":"08b2e44e2e0e63bd","repo":"thephpleague/oauth2-server","slug":"6-the-user-credentials-were-incorrect","errorCode":"6","errorMessage":"The user credentials were incorrect.","messagePattern":"The user credentials were incorrect\\.","errorType":"http","errorClass":"OAuthServerException","httpStatus":400,"severity":"error","filePath":"src/Grant/PasswordGrant.php","lineNumber":101,"sourceCode":"    protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client): UserEntityInterface\n    {\n        $username = $this->getRequestParameter('username', $request)\n            ?? throw OAuthServerException::invalidRequest('username');\n\n        $password = $this->getRequestParameter('password', $request)\n            ?? throw OAuthServerException::invalidRequest('password');\n\n        $user = $this->userRepository->getUserEntityByUserCredentials(\n            $username,\n            $password,\n            $this->getIdentifier(),\n            $client\n        );\n\n        if ($user instanceof UserEntityInterface === false) {\n            $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));\n\n            throw OAuthServerException::invalidCredentials();\n        }\n\n        return $user;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getIdentifier(): string\n    {\n        return 'password';\n    }\n}\n","sourceCodeStart":83,"sourceCodeEnd":115,"githubUrl":"https://github.com/thephpleague/oauth2-server/blob/9d2f6fc0a0b5aa1bb02506971d3a4ecff2c6526c/src/Grant/PasswordGrant.php#L83-L115","documentation":"OAuthServerException::invalidCredentials() produces an 'invalid_credentials' error (code 6) with the message 'The user credentials were incorrect.' The password grant throws it when UserRepository::getUserEntityByUserCredentials returns null/false - i.e. no UserEntity matched the supplied username/password for this grant type and client. Before throwing, it emits a USER_AUTHENTICATION_FAILED event so apps can audit or throttle.","triggerScenarios":"validateUser in PasswordGrant: getUserEntityByUserCredentials($username, $password, grantType, $client) returns something that is not a UserEntityInterface - wrong password, unknown user, credentials valid only for another grant type, or the repository filtering by client.","commonSituations":"User typed the wrong password or an email/username variant that isn't registered; password hashing mismatch after migrating users (bcrypt vs argon2); custom user repository returning null for grant_type scoping it doesn't support; locked or soft-deleted user accounts; test fixtures not seeded in a new environment.","solutions":["Verify the username/password pair is correct and the account exists and is active","Confirm your UserRepository returns a UserEntityInterface and hashes are compared with password_verify against the stored hash","Listen for the USER_AUTHENTICATION_FAILED event to log failed attempts and detect lockouts/brute force","Return null rather than throwing from getUserEntityByUserCredentials so the library surfaces the proper OAuth error"],"exampleFix":"// before\n$user = $this->userRepository->getUserEntityByUserCredentials($username, $password, 'password', $client);\nif ($user === null) { return null; }\n// after (repository side)\nif (password_verify($password, $storedHash)) {\n    return $userEntity; // must implement UserEntityInterface\n}\nreturn null; // library then throws invalidCredentials with code 6","handlingStrategy":"try-catch","validationCode":"if (empty($username) || empty($password)) {\n    // fail fast client-side before invoking the grant\n    throw new \\InvalidArgumentException('Credentials required');\n}","typeGuard":"function credentialsPresent(?string $u, ?string $p): bool {\n    return $u !== null && $u !== '' && $p !== null && $p !== '';\n}","tryCatchPattern":"try {\n    $token = $server->respondToAccessTokenRequest($request, $response);\n} catch (OAuthServerException $e) {\n    if ($e->getMessage() === 'The user credentials were incorrect.') {\n        // show generic auth-failure message; consider rate limiting\n        return $e->generateHttpResponse($response->withStatus(401));\n    }\n    throw $e;\n}","preventionTips":["Return a UserEntityInterface from getUserEntityByUserCredentials on success, null on failure","Compare passwords with password_verify against the stored hash","Emit/listen to USER_AUTHENTICATION_FAILED for auditing and lockout logic","Keep hashing algorithms consistent across user migrations"],"tags":["oauth2","password-grant","invalid-credentials","authentication"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"9d2f6fc0a0b5aa1bb02506971d3a4ecff2c6526c","analyzedAt":"2026-09-15T22:33:30.452Z","contentChangedAt":"2026-09-15T22:33:30.452Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}