thephpleague/oauth2-server · error · OAuthServerException

invalid_request

invalid_request

Error message

The request is missing a required parameter, is invalid, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_id" parameter

What it means

The device authorization request carried no client_id parameter, so DeviceCodeGrant cannot identify which client is requesting a device code. invalidRequest('client_id') produces this RFC6749-style invalid_request message naming the missing parameter.

Solutions

  1. Include client_id in the POSTed form body of the device authorization request
  2. Or send HTTP Basic auth with the client id as username so PHP_AUTH_USER is populated
  3. Ensure the request Content-Type is application/x-www-form-urlencoded so $request->getParsedBody() is populated
  4. Verify the client_id value matches a registered client before calling, since the next step getClientEntityOrFail will also fail on an unknown id

Example fix

// before
curl -X POST https://auth.example.com/device/code

// after
curl -X POST https://auth.example.com/device/code -d 'client_id=my-device-app&scope=basic'
Defensive patterns

Strategy: validation

Validate before calling

$params = (array) $request->getParsedBody(); if (empty($params['client_id']) && empty($request->getServerParams()['PHP_AUTH_USER'])) { return errorResponse('client_id is required'); }

Try / catch

try { $deviceAuth = $grant->respondToDeviceAuthorizationRequest($request, $response); } catch (OAuthServerException $e) { if (str_contains($e->getMessage(), 'client_id')) { return 400 with hint to send client_id; } throw $e; }

Prevention

When it happens

Trigger: POSTing to the device authorization endpoint without a client_id parameter and without PHP_AUTH_USER (HTTP Basic) set; resolving $clientId via getRequestParameter('client_id') falling back to getServerParameter('PHP_AUTH_USER') and both being null.

Common situations: Consumer forgot the client_id field in the form body; requests sent as JSON instead of application/x-www-form-urlencoded so the PSR-7 parsed body is empty; a reverse proxy strips the Authorization Basic header the client relied on; tests hitting the endpoint with no params at all.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of thephpleague/oauth2-server@9d2f6fc0a0 (2026-09-15). Data as JSON: /api/errors/21426e8e3a20487d. Report an issue: GitHub.

Appendix: source

Thrown at src/Grant/DeviceCodeGrant.php:86

     */
    public function canRespondToDeviceAuthorizationRequest(ServerRequestInterface $request): bool
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function respondToDeviceAuthorizationRequest(ServerRequestInterface $request): DeviceCodeResponse
    {
        $clientId = $this->getRequestParameter(
            'client_id',
            $request,
            $this->getServerParameter('PHP_AUTH_USER', $request)
        );

        if ($clientId === null) {
            throw OAuthServerException::invalidRequest('client_id');
        }

        $client = $this->getClientEntityOrFail($clientId, $request);

        $scopes = $this->validateScopes($this->getRequestParameter('scope', $request, $this->defaultScope));

        $deviceCodeEntity = $this->issueDeviceCode(
            $this->deviceCodeTTL,
            $client,
            $this->verificationUri,
            $scopes
        );

        $response = new DeviceCodeResponse();

        if ($this->includeVerificationUriComplete === true) {
            $response->includeVerificationUriComplete();
        }

View on GitHub (pinned to 9d2f6fc0a0)