{"record":{"id":"07be5e2713994011","repo":"thephpleague/oauth2-server","slug":"invalid-client","errorCode":"invalid_client","errorMessage":"invalid_client","messagePattern":"invalid_client","errorType":"http","errorClass":"OAuthServerException","httpStatus":401,"severity":"error","filePath":"src/Grant/AbstractGrant.php","lineNumber":189,"sourceCode":"    /**\n     * Wrapper around ClientRepository::getClientEntity() that ensures we emit\n     * an event and throw an exception if the repo doesn't return a client\n     * entity.\n     *\n     * This is a bit of defensive coding because the interface contract\n     * doesn't actually enforce non-null returns/exception-on-no-client so\n     * getClientEntity might return null. By contrast, this method will\n     * always either return a ClientEntityInterface or throw.\n     *\n     * @throws OAuthServerException\n     */\n    protected function getClientEntityOrFail(string $clientId, ServerRequestInterface $request): ClientEntityInterface\n    {\n        $client = $this->clientRepository->getClientEntity($clientId);\n\n        if ($client instanceof ClientEntityInterface === false) {\n            $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));\n            throw OAuthServerException::invalidClient($request);\n        }\n\n        if ($this->supportsGrantType($client, $this->getIdentifier()) === false) {\n            throw OAuthServerException::unauthorizedClient();\n        }\n\n        return $client;\n    }\n\n    /**\n     * Returns true if the given client is authorized to use the given grant type.\n     */\n    protected function supportsGrantType(ClientEntityInterface $client, string $grantType): bool\n    {\n        return method_exists($client, 'supportsGrantType') === false\n            || $client->supportsGrantType($grantType) === true;\n    }\n","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/thephpleague/oauth2-server/blob/9d2f6fc0a0b5aa1bb02506971d3a4ecff2c6526c/src/Grant/AbstractGrant.php#L171-L207","documentation":"Thrown by AbstractGrant::getClientEntityOrFail when ClientRepository::getClientEntity($clientId) returns anything that is not a ClientEntityInterface (typically null), meaning no client entity exists for the given client_id. The grant emits CLIENT_AUTHENTICATION_FAILED and throws OAuthServerException::invalidClient (HTTP 401, error code 'invalid_client'). Unlike error 10, this is about client lookup/resolution failing, not secret verification.","triggerScenarios":"Any grant flow (validateClient, validateAuthorizationRequest, respondToDeviceAuthorizationRequest) where the client_id passed in the request is not found by your ClientRepository::getClientEntity, or where your repository returns a non-ClientEntity value (null, array, false).","commonSituations":"Typo in client_id in the frontend config; client deleted from the database but still cached in the SPA; getClientEntity returning null because the lookup filters by is_revoked/active flag; a custom repository that returns an array or stdclass instead of a ClientEntityInterface instance; forgetting to register the client in a seeded dev database.","solutions":["Confirm the client_id in the request exists in your client store and that getClientEntity returns a ClientEntityInterface instance for it.","Check your ClientRepository::getClientEntity implementation: make sure it returns the entity, not null/array, and that any active/revoked filtering is not hiding the client.","Verify the client_id string matches exactly (case sensitivity, whitespace, URL-encoding issues).","Ensure the authorization server instance uses the ClientRepository you think it does (DI/container wiring)."],"exampleFix":"// before\npublic function getClientEntity($clientIdentifier) {\n    return $this->pdo->query(\"SELECT * FROM clients WHERE id = ?\", [$clientIdentifier]); // returns array\n}\n// after\npublic function getClientEntity($clientIdentifier): ?ClientEntityInterface {\n    $row = /* fetch row */;\n    if ($row === null) { return null; }\n    $client = new ClientEntity();\n    $client->setIdentifier($row['id']);\n    $client->setRedirectUri(json_decode($row['redirect_uris'], true));\n    $client->setName($row['name']);\n    return $client;\n}","handlingStrategy":"try-catch","validationCode":"// pre-flight lookup in your own store before calling the server\n$stmt = $pdo->prepare('SELECT id FROM oauth_clients WHERE id = ? AND revoked = 0');\n$stmt->execute([$clientId]);\nif ($stmt->fetch() === false) {\n    throw new \\InvalidArgumentException(\"Unknown client_id: {$clientId}\");\n}","typeGuard":"function isClientFound($clientEntity): bool {\n    return $clientEntity instanceof \\League\\OAuth2\\Server\\Entities\\ClientEntityInterface;\n}","tryCatchPattern":"try {\n    $authRequest = $server->validateAuthorizationRequest($request);\n} catch (OAuthServerException $e) {\n    if ($e->getErrorType() === 'invalid_client') {\n        // client_id not resolvable: return 401 with helpful message\n    }\n    return $e->generateHttpResponse($response);\n}","preventionTips":["Unit-test ClientRepository::getClientEntity for both found and not-found client_ids.","Always return a ClientEntityInterface or null — never arrays/false — from getClientEntity.","Keep client registration in sync between environments with seed scripts.","Trim and normalize client_id input before lookup."],"tags":["oauth2","php","client-not-found","invalid-client"],"backgroundTag":"resource-not-found","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"}