Documentation Index
Fetch the complete documentation index at: https://noorle.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
OAuth Device Flow (RFC 8628) is designed for CLI tools, headless servers, and devices without browsers. Users authorize on their device, and the CLI receives tokens without handling passwords.
Why Device Flow?
Traditional OAuth (Browser-based)
Problem: Browser redirect complex for CLI tools.
Device Flow (CLI-friendly)
Better: CLI asks user to visit URL, handles polling.
How Device Flow Works
Device Flow Endpoints
Step 1: Request Device Code
POST https://api.noorle.com/oauth/device/authorize
Body:
{
"client_id": "noorle-cli"
}
Response:
{
"device_code": "abcd1234567890",
"user_code": "XYZ-789",
"verification_uri": "https://auth.noorle.com/device",
"verification_uri_complete": "https://auth.noorle.com/device?user_code=XYZ-789",
"expires_in": 1800, // 30 minutes
"interval": 5 // poll every 5 seconds
}
Step 2: User Authorizes
User visits verification URL:
https://auth.noorle.com/device?user_code=XYZ-789
CLI should display:
Visit: https://auth.noorle.com/device
Code: XYZ-789
Waiting for authorization...
Step 3: Poll for Token
CLI polls until user approves (or times out):
POST https://api.noorle.com/oauth/token
Body:
{
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"device_code": "abcd1234567890",
"client_id": "noorle-cli"
}
Response (pending):
{
"error": "authorization_pending"
}
(wait 5 seconds, retry)
Response (after user approves):
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 3600, // 1 hour
"token_type": "Bearer",
"scope": "read write execute"
}
CLI Example: Noorle Login
$ noorle login
? Which account? (use arrow keys)
❯ account-1 (alice@example.com)
account-2 (work account)
To authorize, visit:
https://auth.noorle.com/device
Code: XYZ-789
Waiting for authorization... ✓
Successfully authenticated!
Token saved to ~/.noorle/credentials.json
Behind the Scenes
#!/bin/bash
# Step 1: Request device code
RESPONSE=$(curl -s -X POST \
https://api.noorle.com/oauth/device/authorize \
-d "client_id=noorle-cli")
DEVICE_CODE=$(echo $RESPONSE | jq '.device_code')
USER_CODE=$(echo $RESPONSE | jq '.user_code')
VERIFY_URL=$(echo $RESPONSE | jq '.verification_uri_complete')
# Step 2: Display to user
echo "Visit: $VERIFY_URL"
echo "Code: $USER_CODE"
echo "Waiting for authorization..."
# Step 3: Poll for token
while true; do
TOKEN=$(curl -s -X POST \
https://api.noorle.com/oauth/token \
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
-d "device_code=$DEVICE_CODE" \
-d "client_id=noorle-cli")
ERROR=$(echo $TOKEN | jq '.error')
if [ "$ERROR" != "authorization_pending" ]; then
break
fi
sleep 5
done
# Step 4: Store token
echo $TOKEN | jq '.access_token' > ~/.noorle/token.json
echo "Authorized!"
Token Storage
Tokens should be stored securely:
Linux/Mac
# Store in secure file with restricted permissions
~/.noorle/credentials.json
(permissions: 600 - owner readable/writable only)
Content:
{
"access_token": "eyJhbGc...",
"refresh_token": "eyJhbGc...",
"expires_at": 1711183000,
"scope": "read write execute"
}
Windows
%APPDATA%\Noorle\credentials.json
(permissions: NTFS ACLs - user only)
Content: (same as Linux/Mac)
Docker/Container
# Pass token via environment variable
docker run -e NOORLE_TOKEN="eyJhbGc..." myapp
Token Refresh
Access tokens expire (default 1 hour). Use refresh token to get new access token:
POST https://api.noorle.com/oauth/token
Body:
{
"grant_type": "refresh_token",
"refresh_token": "eyJhbGc...",
"client_id": "noorle-cli"
}
Response:
{
"access_token": "new-eyJhbGc...",
"refresh_token": "new-eyJhbGc...",
"expires_in": 3600,
"token_type": "Bearer"
}
CLI should auto-refresh before expiration:
# Check expiration
EXPIRES_AT=$(jq '.expires_at' ~/.noorle/credentials.json)
NOW=$(date +%s)
if [ $EXPIRES_AT -lt $((NOW + 300)) ]; then
# Token expires in < 5 minutes, refresh now
curl -X POST ... (refresh token request)
# Store new token
fi
Using Tokens in CLI
Once authenticated, CLI sends token automatically:
# Get stored token
TOKEN=$(jq -r '.access_token' ~/.noorle/credentials.json)
# Make API request
curl -H "Authorization: Bearer $TOKEN" \
https://api.noorle.com/agents
Most CLI tools hide this:
# User just runs commands
$ noorle agents list
Research Agent
Support Bot
Analyst
# CLI automatically:
# 1. Loads token from ~/.noorle/credentials.json
# 2. Includes it in Authorization header
# 3. Refreshes if needed
Logout
Remove tokens:
$ noorle logout
Are you sure? (y/n) y
Logged out. Token removed.
Implementation:
# Remove token file
rm ~/.noorle/credentials.json
# Optionally revoke token on server
curl -X POST https://api.noorle.com/oauth/revoke \
-d "token=eyJhbGc..."
Scopes
Request specific permissions via scope:
POST https://api.noorle.com/oauth/device/authorize
Body:
{
"client_id": "noorle-cli",
"scope": "read execute" // only read + execute, no manage
}
Available scopes:
read - View resources (list, get)
execute - Run agents, call tools
manage - Create, update resources
admin - Delete, full control
offline_access - Request refresh token
Example:
# Read-only CLI (can't accidentally break anything)
noorle login --scope "read"
# Bot that executes only
noorle login --scope "execute"
# Admin tool with full access
noorle login --scope "read write execute manage admin offline_access"
Security Considerations
1. User Code
User code (e.g., XYZ-789) is short and memorable. Users must carefully enter it. Risks:
Risk: User types wrong code
└─ Typo grants access to attacker
Mitigation:
├─ Code is only valid for 30 minutes
├─ Code must be entered exactly
└─ Mismatches logged
2. Device Code
Device code is the secret. Keep it private:
Risk: Device code leaked
└─ Attacker can poll and get tokens
Mitigation:
├─ Only valid for 30 minutes
├─ One-time use (can't reuse same code)
└─ Revoked on first error
3. Token Storage
Access token on disk is sensitive:
Risk: Disk compromised
└─ Attacker gets access token
Mitigation:
├─ File permissions: 600 (owner only)
├─ Use OS secure storage if possible
├─ Tokens expire after 1 hour
└─ Refresh tokens rotated on use
4. Revocation
Users can revoke tokens anytime:
Console → Settings → Connected Apps
├─ CLI: noorle-cli
│ ├─ Authorized: 2024-03-22
│ ├─ Last used: 2024-03-22 14:30
│ └─ [Revoke]
│ └─ All tokens immediately invalid
Troubleshooting
| Problem | Solution |
|---|
| ”authorization_pending” (forever) | User didn’t approve. Check verification URL was visited. |
| ”invalid_request” | Check client_id is correct. Verify device code format. |
| ”Token expired” | Refresh token. Use refresh_token endpoint. |
| Code expires in 30 min | User took too long. Start over with noorle login. |
| Can’t find stored token | Check ~/.noorle/credentials.json exists. Verify permissions. |
Next: Learn about JWT Tokens for stateless authentication.