{"record":{"id":"8b08f7a9e2f2f256","repo":"thephpleague/oauth2-server","slug":"invalid-client-authentication-failed","errorCode":"invalid_client","errorMessage":"Client authentication failed","messagePattern":"Client authentication failed","errorType":"http","errorClass":"OAuthServerException","httpStatus":401,"severity":"error","filePath":"src/Grant/ImplicitGrant.php","lineNumber":117,"sourceCode":"            $this->getServerParameter('PHP_AUTH_USER', $request)\n        );\n\n        if (is_null($clientId)) {\n            throw OAuthServerException::invalidRequest('client_id');\n        }\n\n        $client = $this->getClientEntityOrFail($clientId, $request);\n\n        $redirectUri = $this->getQueryStringParameter('redirect_uri', $request);\n\n        if ($redirectUri !== null) {\n            $this->validateRedirectUri($redirectUri, $client, $request);\n        } elseif (\n            $client->getRedirectUri() === '' ||\n            (is_array($client->getRedirectUri()) && count($client->getRedirectUri()) !== 1)\n        ) {\n            $this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));\n            throw OAuthServerException::invalidClient($request);\n        }\n\n        $stateParameter = $this->getQueryStringParameter('state', $request);\n\n        $scopes = $this->validateScopes(\n            $this->getQueryStringParameter('scope', $request, $this->defaultScope),\n            $this->makeRedirectUri(\n                $redirectUri ?? $this->getClientRedirectUri($client),\n                $stateParameter !== null ? ['state' => $stateParameter] : [],\n                $this->queryDelimiter\n            )\n        );\n\n        $authorizationRequest = $this->createAuthorizationRequest();\n        $authorizationRequest->setGrantTypeId($this->getIdentifier());\n        $authorizationRequest->setClient($client);\n        $authorizationRequest->setRedirectUri($redirectUri);\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/thephpleague/oauth2-server/blob/9d2f6fc0a0b5aa1bb02506971d3a4ecff2c6526c/src/Grant/ImplicitGrant.php#L99-L135","documentation":"OAuthServerException::invalidClient signals failed client authentication. In ImplicitGrant it is thrown when the client has no usable redirect URI: an empty redirectUri, or an array of redirect URIs containing more/less than exactly one entry. Since the implicit flow redirects responses, the grant requires a single, reliable registered redirect URI.","triggerScenarios":"validateAuthorizationRequest -> getClientEntityOrFail succeeds but the client entity's getRedirectUri() returns '' or an array with count !== 1; the grant emits CLIENT_AUTHENTICATION_FAILED and throws invalidClient.","commonSituations":"Client entity returned by a custom ClientRepository has an empty redirect_uri field; developer returns all registered redirect URIs as an array when the implicit grant expects exactly one; database row with NULL/blank redirect_uri; migrate from another grant type that tolerated multiple redirect URIs.","solutions":["Fix your ClientRepository/getClientEntity to return a client whose redirectUri is a single non-empty string for implicit flow clients","If storing multiple redirect URIs, return only the one matching the request instead of the whole array","Update the client record so redirect_uri is populated in your persistence layer","Alternatively use the auth-code grant, which supports redirect URI validation differently"],"exampleFix":"// before\npublic function getClientEntity($id, ...): ClientEntityInterface {\n    $client->setRedirectUri($allRedirectUris); // array of 3 URIs\n}\n// after\n$client->setRedirectUri('https://app.example.com/callback'); // single exact URI for implicit clients","handlingStrategy":"validation","validationCode":"$client = $clientRepository->getClientEntity($clientId, 'implicit', null, false);\n$uri = $client->getRedirectUri();\nif ($uri === '' || (is_array($uri) && count($uri) !== 1)) {\n    throw new \\RuntimeException('Implicit-flow clients need exactly one non-empty redirect URI');\n}","typeGuard":"function hasUsableRedirectUri(ClientEntityInterface $c): bool {\n    $u = $c->getRedirectUri();\n    return is_string($u) && $u !== '' || (is_array($u) && count($u) === 1);\n}","tryCatchPattern":"try {\n    $authRequest = $server->validateAuthorizationRequest($request);\n} catch (OAuthServerException $e) {\n    if ($e->getErrorType() === 'invalid_client') {\n        // show error page; fix client record's redirect_uri\n    }\n    throw $e;\n}","preventionTips":["Return a single redirect URI string from getClientEntity for implicit clients","Add DB constraints ensuring redirect_uri is non-empty for registered clients","Validate client registration data at write time, not only at authorization time"],"tags":["oauth2","implicit-grant","invalid-client","redirect-uri"],"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-16T09:17:16.951Z"}