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
- Include client_id in the POSTed form body of the device authorization request
- Or send HTTP Basic auth with the client id as username so PHP_AUTH_USER is populated
- Ensure the request Content-Type is application/x-www-form-urlencoded so $request->getParsedBody() is populated
- 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
- POST as application/x-www-form-urlencoded with client_id present
- Prefer explicit body client_id over relying on Basic-auth PHP_AUTH_USER
- Validate client_id against registered clients before dispatching to the grant
- Check proxies don't strip Authorization headers if relying on Basic auth
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
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)