Appearance
Device Code Flow
The device authorization grant is designed for devices that have limited input capability — CLI tools, smart TVs, IoT devices — where the user authorizes on a separate device (like their phone or laptop).
When to Use
- CLI tools and terminal applications
- Devices without a browser (IoT, set-top boxes)
- Environments where redirect-based flows aren't feasible
Flow Overview
Step 1: Request Device Code
bash
curl -X POST /oauth/device/authorize \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=YOUR_CLIENT_ID" \
-d "scope=openid projects:read"Response:
json
{
"device_code": "DEVICE_CODE",
"user_code": "ABCD-1234",
"verification_uri": "https://developer.knowify.com/device",
"verification_uri_complete": "https://developer.knowify.com/device?user_code=ABCD-1234",
"expires_in": 600,
"interval": 5
}Step 2: Display Instructions
Show the user:
To authorize this device, visit:
https://developer.knowify.com/device
And enter code: ABCD-1234Step 3: Poll for Token
While the user authorizes, poll the token endpoint at the specified interval:
bash
curl -X POST /oauth/token \
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
-d "device_code=DEVICE_CODE" \
-d "client_id=YOUR_CLIENT_ID"Possible responses while waiting:
| Error | Meaning |
|---|---|
authorization_pending | User hasn't authorized yet — keep polling |
slow_down | Polling too fast — increase interval by 5 seconds |
expired_token | The device code expired — start over |
access_denied | User denied the request |
Once approved, you receive the token response:
json
{
"access_token": "eyJhbG...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "ey...",
"scope": "openid projects:read"
}Polling Example
javascript
async function pollForToken(deviceCode, clientId, interval = 5) {
while (true) {
await new Promise(r => setTimeout(r, interval * 1000));
const res = await fetch('/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
device_code: deviceCode,
client_id: clientId,
}),
});
const data = await res.json();
if (data.access_token) return data;
if (data.error === 'slow_down') interval += 5;
if (data.error === 'expired_token') throw new Error('Device code expired');
if (data.error === 'access_denied') throw new Error('User denied access');
}
}