{"record":{"id":"f92e1c2cb0e2bc16","repo":"thephpleague/oauth2-server","slug":"invalid-grant-the-authorization-type-is-not-supported-by-the","errorCode":"invalid_grant","errorMessage":"The authorization grant type is not supported by the authorization server.","messagePattern":"The authorization grant type is not supported by the authorization server\\.","errorType":"http","errorClass":"OAuthServerException","httpStatus":400,"severity":"error","filePath":"src/Grant/DeviceCodeGrant.php","lineNumber":205,"sourceCode":"    /**\n     * @throws OAuthServerException\n     */\n    protected function validateDeviceCode(ServerRequestInterface $request, ClientEntityInterface $client): DeviceCodeEntityInterface\n    {\n        $deviceCode = $this->getRequestParameter('device_code', $request);\n\n        if (is_null($deviceCode)) {\n            throw OAuthServerException::invalidRequest('device_code');\n        }\n\n        $deviceCodeEntity = $this->deviceCodeRepository->getDeviceCodeEntityByDeviceCode(\n            $deviceCode\n        );\n\n        if ($deviceCodeEntity instanceof DeviceCodeEntityInterface === false) {\n            $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));\n\n            throw OAuthServerException::invalidGrant();\n        }\n\n        if (time() > $deviceCodeEntity->getExpiryDateTime()->getTimestamp()) {\n            throw OAuthServerException::expiredToken('device_code');\n        }\n\n        if ($this->deviceCodeRepository->isDeviceCodeRevoked($deviceCode) === true) {\n            throw OAuthServerException::invalidRequest('device_code', 'Device code has been revoked');\n        }\n\n        if ($deviceCodeEntity->getClient()->getIdentifier() !== $client->getIdentifier()) {\n            throw OAuthServerException::invalidRequest('device_code', 'Device code was not issued to this client');\n        }\n\n        return $deviceCodeEntity;\n    }\n\n    private function deviceCodePolledTooSoon(?DateTimeImmutable $lastPoll): bool","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/thephpleague/oauth2-server/blob/9d2f6fc0a0b5aa1bb02506971d3a4ecff2c6526c/src/Grant/DeviceCodeGrant.php#L187-L223","documentation":"The supplied device_code did not resolve to a DeviceCodeEntityInterface, meaning the authorization server has no record of it. validateDeviceCode() emits USER_AUTHENTICATION_FAILED and throws invalidGrant() with the generic unsupported-grant-type-style message because a device flow token request was made with an unknown device code.","triggerScenarios":"respondToAccessTokenRequest -> validateDeviceCode with a device_code string that was never issued, already consumed/rotated, deleted by storage pruning, or stored/read via mismatched repository backends (persist to one store, read from another).","commonSituations":"Client restarted the flow but kept polling with the old device_code; multi-server deployment where device codes are stored in local cache/file instead of shared storage (Redis/DB); codes expired and were garbage-collected; fabricated or truncated codes from a misbehaving client.","solutions":["Use the exact device_code from the current device authorization response; restart the device flow if it was consumed","Persist device codes in shared storage (Redis/DB) so all server nodes see them","Fix DeviceCodeRepository::getDeviceCodeEntityByDeviceCode to return the hydrated entity for valid codes and null otherwise","Check pruning jobs and TTLs are not removing codes before their expiry"],"exampleFix":"// before (local file cache per server node)\n$store = new FileStore('/tmp/device-codes');\n\n// after (shared store)\n$store = new RedisStore($redis, 'device_codes');","handlingStrategy":"try-catch","validationCode":"$entity = $repo->getDeviceCodeEntityByDeviceCode($code); if ($entity === null) { restartDeviceFlow(); }","typeGuard":"function deviceCodeExists(?DeviceCodeEntityInterface $e): bool { return $e instanceof DeviceCodeEntityInterface; }","tryCatchPattern":"try { pollToken(); } catch (OAuthServerException $e) { if ($e->getErrorType() === 'invalid_grant') { restartDeviceFlow('Unknown device code'); return; } throw $e; }","preventionTips":["Restart the flow whenever the device code is unknown or consumed","Store device codes in shared storage across server nodes","Never reuse device_code values from previous authorization rounds","Verify repository read/write backends match"],"tags":["oauth2","device-flow","invalid-grant"],"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"}