The Device Code Flow enables authentication for applications where secure credential storage is challenging, such as desktop software or offline client-server applications.
- Desktop applications: Medical practice management software
- Offline applications: Client-server systems with limited internet connectivity
- Limited input devices: Applications where entering credentials is difficult
┌─────────────────┐
│ Your Application│
└────────┬────────┘
│ 1. Request device code
▼
┌──────────┐
│ Askara │
└────┬─────┘
│ 2. Return device code & user code
▼
┌─────────────────┐
│ Your Application│
└────────┬────────┘
│ 3. Display user code & URL
▼
┌──────────┐
│ User │
└────┬─────┘
│ 4. Visit URL & enter code
▼
┌──────────┐
│ Askara │
└────┬─────┘
│ 5. Show login/consent page
▼
┌──────────┐
│ User │
└────┬─────┘
│ 6. Authorize application
▼
┌──────────┐
│ Askara │
└────┬─────┘
│
│ ┌─────────────────────────┐
│ │ 7. Polling loop │
│ │ │
┌─────────────────┐ │
│ Your Application│◄─────────────────┘
└────────┬────────┘ authorization_pending
│
│ (continues polling...)
│
┌────▼─────┐
│ Askara │
└────┬─────┘
│ 8. Return access & refresh tokens
▼
┌─────────────────┐
│ Your Application│
└─────────────────┘Unlike the Authorization Code Flow, the user authenticates on a separate device (phone, computer) by entering a short code.
Your application requests a device code from Askara. Make sure to replace CLIENT_ID with your client identifier and to use the desired scopes.
POST https://api.askara.ai/oauth2/device-authorization
Content-Type: application/x-www-form-urlencoded
client_id=CLIENT_ID&scope=profile organizationResponse:
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "BDWP-HQPK",
"verification_uri": "https://app.askara.ai/device-verify",
"expires_in": 600,
"interval": 5
}Response fields:
device_code: Used for polling (keep secure)user_code: Short code displayed to user (e.g., "BDWP-HQPK")verification_uri: URL where user enters the codeexpires_in: Code validity period in seconds (10 minutes)interval: Minimum seconds between polling requests
Show the user how to authorize the application. Provide multiple options:
Option 1: Manual Code Entry
1. Visit: https://app.askara.ai/device-verify
2. Enter code: BDWP-HQPK
3. Authorize the applicationOption 2: QR Code Generate a QR code from the verification URI for quick mobile access.
Option 3: Direct Link Provide a clickable link to the verification URI.
Poll the token endpoint while waiting for user authorization:
POST https://api.askara.ai/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS&client_id=CLIENT_IDImportant: Respect the interval value to avoid rate limiting. Poll every 5 seconds (or as specified).
{
"error": "authorization_pending",
"error_description": "User has not yet authorized the device"
}Action: Continue polling.
{
"error": "slow_down",
"error_description": "Polling too frequently"
}Action: Increase polling interval by 5 seconds.
{
"token_type": "Bearer",
"expires_in": 3600,
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "def502003f8a8c7..."
}Action: Store tokens and stop polling.
{
"error": "expired_token",
"error_description": "The device code has expired"
}Action: Start over from Step 1.
// Step 1: Request device code
$response = $httpClient->post('https://api.askara.ai/oauth2/device-authorization', [
'form_params' => [
'client_id' => getenv('ASKARA_CLIENT_ID'),
'scope' => 'profile organization'
]
]);
$deviceData = json_decode($response->getBody(), true);
// Step 2: Display to user
echo "Visit: {$deviceData['verification_uri']}\n";
echo "Enter code: {$deviceData['user_code']}\n";
echo "Or scan this QR code:\n";
displayQRCode($deviceData['verification_uri']);
// Step 3: Poll for authorization
$interval = $deviceData['interval'];
$expiresAt = time() + $deviceData['expires_in'];
while (time() < $expiresAt) {
sleep($interval);
try {
$tokenResponse = $httpClient->post('https://api.askara.ai/oauth2/token', [
'form_params' => [
'grant_type' => 'urn:ietf:params:oauth:grant-type:device_code',
'device_code' => $deviceData['device_code'],
'client_id' => getenv('ASKARA_CLIENT_ID')
]
]);
$tokens = json_decode($tokenResponse->getBody(), true);
// Success! Store tokens
storeTokens($tokens);
echo "Authorization successful!\n";
break;
} catch (HttpException $e) {
$error = json_decode($e->getResponse()->getBody(), true);
if ($error['error'] === 'authorization_pending') {
// Keep waiting
continue;
}
if ($error['error'] === 'slow_down') {
// Increase interval
$interval += 5;
continue;
}
// Other error (expired, denied, etc.)
echo "Authorization failed: {$error['error_description']}\n";
break;
}
}- Display the verification URL prominently
- Format the user code for readability (e.g., "BDWP-HQPK" not "bdwphqpk")
- Show expiration time to create urgency
- Provide QR code for mobile users
- Offer clickable link for desktop users
- Include manual entry for maximum compatibility
⏳ Waiting for authorization...
Visit: https://app.askara.ai/device-verify
Code: BDWP-HQPK
Expires in: 8:32❌ Authorization expired
The code has expired. Click here to generate a new code.- Device codes are bearer tokens - keep them secure
- Don't log or expose device codes in error messages
- Codes expire after 10 minutes
- Respect the
intervalparameter - Handle
slow_downerrors appropriately - Implement exponential backoff for repeated failures
For desktop applications, client secrets cannot be kept confidential. Consider:
- Using public client configuration (no secret required)
- Implementing additional security measures (PKCE)
- Contact us to discuss your specific use case
| Feature | Device Code | Authorization Code |
|---|---|---|
| Redirect required | No | Yes |
| User enters code | Yes | No |
| Client secret | Optional | Required |
| Best for | Desktop apps | Web apps |
| User device | Any device | Same device |
- Refresh Token Flow - Renew expired tokens
- Authorization Code Flow - Alternative for web apps
- OAuth2 Overview - All authentication flows