BDFK-RSTV. The user opens a URL on their phone or laptop, signs in, types the code, and the waiting device gets a session. No credentials ever travel through the constrained device.
Setup
Add the plugin
lib/kavach.ts
Build the user-facing approval page
Create a page at yourverificationUri. It should let a signed-in user enter the code the device is showing and approve or deny the request.app/device/page.tsx (Next.js)
/auth/device/authorize endpoint requires an active session. The user must be signed in before they can approve or deny a device code.Device flow
Request codes (on the device)
POST /auth/device/codeThe device calls this endpoint to start a new authorization attempt. No authentication required.CLI tool
user_code prominently, this is what the user types. verification_uri_complete includes the code as a query parameter, so you can also show a QR code for it.Poll for authorization (on the device)
POST /auth/device/tokenPoll this endpoint at the interval returned in the previous step (default: every 5 seconds). Keep polling until you get an authorized response or the code expires.CLI tool
User approves (on the secondary device)
The user opensverification_uri on their phone or laptop, signs in, and enters the code. The approval page calls /auth/device/authorize with the user code and action: 'approve'. The next poll from the device returns { authorized: true, user_id: '...' }.User code format
User codes use the formatXXXX-XXXX, two four-character segments separated by a hyphen. The character set is consonants only (BCDFGHJKLMNPQRSTVWXZ), which avoids:
- Visually ambiguous characters (no
0/O,1/I,5/S) - Characters that read awkwardly when pronounced aloud
codeLength option controls the length of each segment (default: 4).
Input on the approval page is case-insensitive and whitespace-tolerant, bdfk rstv, BDFK-RSTV, and BDFKRSTV all resolve to the same grant.
Polling interval and slow-down
The initial interval is returned by the/auth/device/code endpoint (default: 5 seconds). The server enforces a minimum gap between polls. If the device polls too quickly, the response includes error: 'slow_down' and an updated interval value. The device must use the new interval for all subsequent polls.
Endpoints
| Endpoint | Method | Auth required | Description |
|---|---|---|---|
/auth/device/code | POST | No | Start a new device flow, returns device code and user code |
/auth/device/token | POST | No | Poll for authorization status |
/auth/device/authorize | POST | Yes | User approves or denies a device code |
/auth/device/code response
| Field | Type | Description |
|---|---|---|
device_code | string | Opaque code used for polling. Keep this secret on the device |
user_code | string | Short human-readable code shown to the user (e.g. BDFK-RSTV) |
verification_uri | string | URL the user visits to approve |
verification_uri_complete | string | Same URL with user_code as a query param, useful for QR codes |
expires_in | number | Seconds until the codes expire (default: 900) |
interval | number | Minimum seconds between poll requests (default: 5) |
/auth/device/token error codes
error | Meaning |
|---|---|
authorization_pending | User has not acted yet, keep polling |
slow_down | Polling too fast, use the new interval in the response |
access_denied | User denied the request, stop polling |
expired_token | Code has expired, start over with a new code |
Configuration reference
| Option | Type | Default | Description |
|---|---|---|---|
verificationUri | string | required | URL the user visits to enter the code and approve |
codeLength | number | 4 | Length of each segment in the user code (4 → XXXX-XXXX) |
codeExpirySeconds | number | 900 | How long the device code and user code stay valid |
pollIntervalSeconds | number | 5 | Minimum interval between polling attempts, returned to the device |