Project 21: “The Headless Server Setup” — Remote Development
| Attribute | Value |
|---|---|
| File | KIRO_CLI_LEARNING_PROJECTS.md |
| Main Programming Language | Linux Shell |
| Coolness Level | Level 3: Genuinely Clever |
| Difficulty | Level 2: Intermediate |
| Knowledge Area | Remote Development |
What you’ll build: Install Kiro on a headless VM and authenticate via device flow.
Why it teaches Remote Dev: This is the standard pattern for server-based work.
Success criteria:
- Headless login succeeds without a local browser.
Real World Outcome
You’ll have Kiro running on a headless Linux server (no GUI, no browser) and successfully authenticated via OAuth device flow. This enables server-side automation, CI/CD integration, and remote development workflows:
Successful headless authentication:
# On remote server (no GUI)
$ ssh user@dev-server.company.com
$ kiro auth login
Kiro CLI Authentication (Device Flow)
═══════════════════════════════════════
No browser detected. Using device code flow.
1. Visit this URL on any device with a browser:
https://anthropic.com/device
2. Enter this code: ABCD-EFGH
3. Authorize the Kiro CLI application
Waiting for authorization... (timeout in 10 minutes)
[User visits URL on laptop, enters code, approves]
✓ Authentication successful!
✓ Token stored in: ~/.kiro/credentials.json
✓ Expires in: 30 days
$ kiro "show me system info"
Kiro: [Returns server specs, uptime, disk usage]
# Headless session is now active
Automated server setup:
$ cat setup-headless-kiro.sh
#!/bin/bash
# Install and configure Kiro on headless servers
# Install Kiro CLI
curl -fsSL https://kiro.dev/install.sh | bash
# Verify installation
kiro --version
# Authenticate (device flow)
echo "Follow the URL and enter the code displayed"
kiro auth login
# Verify authentication
kiro auth whoami
# Set up SSH agent forwarding (optional)
echo 'Host dev-server' >> ~/.ssh/config
echo ' ForwardAgent yes' >> ~/.ssh/config
echo "✓ Kiro headless setup complete"
CI/CD integration example:
# .github/workflows/deploy.yml
name: Deploy with Kiro
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Kiro
run: curl -fsSL https://kiro.dev/install.sh | bash
- name: Authenticate Kiro (service account)
env:
KIRO_API_KEY: ${{ secrets.KIRO_API_KEY }}
run: kiro auth login --api-key $KIRO_API_KEY
- name: Run deployment
run: kiro "deploy to staging using docker-compose"
This setup unlocks server-side AI automation where Kiro can manage infrastructure, run deployments, and execute maintenance tasks—all without human intervention.
The Core Question You’re Answering
“How do I use an AI coding assistant on remote servers that don’t have browsers or GUIs?”
Before you start coding, consider: Most cloud services use OAuth for authentication, which requires opening a browser to authorize. But servers don’t have browsers—they’re headless. The device flow (RFC 8628) solves this by splitting authentication into two steps: the headless device gets a code, and you enter that code on any browser-enabled device. This project teaches you to bridge local and remote authentication workflows.
Concepts You Must Understand First
Stop and research these before coding:
- OAuth Device Authorization Grant (Device Flow)
- What is the device code flow (RFC 8628)?
- How does it differ from standard OAuth (authorization code flow)?
- What are the steps: device code request → user authorization → token polling?
- How do you handle timeout (user doesn’t authorize within 10 minutes)?
- Book Reference: “OAuth 2 in Action” by Justin Richer - Ch. 12 (Device Flow)
- SSH Agent Forwarding
- What is
ForwardAgent yesin SSH config? - How do you forward local credentials to remote sessions?
- What are the security risks of agent forwarding?
- When should you use ProxyJump vs ForwardAgent?
- Book Reference: “SSH Mastery” by Michael W. Lucas - Ch. 6 (Agent Forwarding)
- What is
- Headless Environment Detection
- How do you detect if a display is available (
$DISPLAY,$WAYLAND_DISPLAY)? - How do you check if
xdg-openoropencommands work? - What’s the difference between TTY and pseudo-TTY sessions?
- How do you determine if running in a CI/CD environment?
- Book Reference: “The Linux Programming Interface” by Michael Kerrisk - Ch. 62 (Terminals)
- How do you detect if a display is available (
- Credential Storage and Rotation
- Where should tokens be stored (
~/.kiro/credentials.json)? - What file permissions are required for security (600)?
- How do you handle token expiration and refresh?
- Should you use environment variables vs config files?
- Book Reference: “Building Secure and Reliable Systems” by Google - Ch. 9 (Secrets Management)
- Where should tokens be stored (
Questions to Guide Your Design
Before implementing, think through these:
- Authentication Method Selection
- How do you detect if a browser is available vs requiring device flow?
- Should you support both interactive and non-interactive modes?
- How do you handle service accounts (API keys) vs user accounts (OAuth)?
- What happens if the device code expires before authorization?
- Token Management
- Where do you store the access token (file, keyring, environment)?
- How do you secure the token file (permissions, encryption)?
- Do you need a refresh token for long-running servers?
- How often should you validate the token (every command, daily)?
- CI/CD Integration
- How do you authenticate in GitHub Actions/GitLab CI without interaction?
- Should you use service accounts or personal access tokens?
- How do you rotate tokens in CI without manual intervention?
- What’s the fallback if authentication fails mid-pipeline?
- Debugging Headless Issues
- How do you debug authentication failures without a GUI?
- Should you log to a file (
~/.kiro/debug.log) or stderr? - How do you test device flow locally before deploying to servers?
- What telemetry do you need (auth attempts, failures, timeouts)?
Thinking Exercise
Manual Device Flow Authentication Walkthrough
Before writing code, trace the OAuth device flow step by step:
Step 1: Kiro detects headless environment
$ kiro auth login
# Check for browser availability
if ! command -v xdg-open &>/dev/null && [ -z "$DISPLAY" ]; then
# Headless mode detected
use_device_flow=true
fi
Step 2: Request device code from Anthropic
POST https://anthropic.com/oauth/device/code
Content-Type: application/json
{
"client_id": "kiro-cli",
"scope": "kiro.read kiro.write"
}
Response:
{
"device_code": "DEVICE-12345",
"user_code": "ABCD-EFGH",
"verification_uri": "https://anthropic.com/device",
"expires_in": 600,
"interval": 5
}
Step 3: Display instructions to user
1. Visit: https://anthropic.com/device
2. Enter code: ABCD-EFGH
3. Authorize Kiro CLI
Step 4: Poll for authorization
# Poll every 5 seconds for up to 600 seconds
while [ $elapsed -lt 600 ]; do
POST https://anthropic.com/oauth/token
{
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"device_code": "DEVICE-12345",
"client_id": "kiro-cli"
}
# Response if pending:
{ "error": "authorization_pending" }
# Response if approved:
{
"access_token": "kiro_...",
"token_type": "Bearer",
"expires_in": 2592000
}
sleep 5
done
Step 5: Store token securely
echo "$access_token" > ~/.kiro/credentials.json
chmod 600 ~/.kiro/credentials.json
Questions while tracing:
- What happens if the user never authorizes (timeout)?
- How do you handle polling errors (network failures)?
- Should you provide a QR code for mobile authorization?
- How do you test this without hitting real OAuth servers?
The Interview Questions They’ll Ask
Prepare to answer these:
- “Explain the OAuth device flow (RFC 8628) and how it differs from the standard authorization code flow. When would you use each?”
- “How would you securely store OAuth tokens on a headless server? What file permissions and encryption methods would you use?”
- “What strategies would you use to detect if a system is headless vs has a GUI available?”
- “How do you implement token refresh in a long-running server application without user interaction?”
- “Explain the security implications of SSH agent forwarding. When is it safe to use, and what are the alternatives?”
- “How would you design a CI/CD integration for an OAuth-authenticated tool without exposing tokens in logs?”
Hints in Layers
Hint 1: Detect Headless Environment Check for display availability before attempting browser launch:
if [ -z "$DISPLAY" ] && ! command -v xdg-open &>/dev/null; then
echo "No browser detected. Using device code flow."
device_flow=true
fi
Hint 2: Use curl for OAuth API Calls Request device code:
response=$(curl -s -X POST https://anthropic.com/oauth/device/code \
-H "Content-Type: application/json" \
-d '{"client_id": "kiro-cli", "scope": "kiro.read kiro.write"}')
device_code=$(echo "$response" | jq -r '.device_code')
user_code=$(echo "$response" | jq -r '.user_code')
verification_uri=$(echo "$response" | jq -r '.verification_uri')
Hint 3: Poll with Exponential Backoff Don’t hammer the server every second:
interval=5
max_attempts=120 # 10 minutes / 5 seconds
for i in $(seq 1 $max_attempts); do
token_response=$(curl -s -X POST https://anthropic.com/oauth/token \
-d "grant_type=device_code&device_code=$device_code&client_id=kiro-cli")
if echo "$token_response" | jq -e '.access_token' &>/dev/null; then
echo "✓ Authentication successful!"
break
fi
sleep $interval
done
Hint 4: Secure Token Storage
mkdir -p ~/.kiro
echo "$access_token" > ~/.kiro/credentials.json
chmod 600 ~/.kiro/credentials.json # Owner read/write only
Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| OAuth Device Flow | “OAuth 2 in Action” by Justin Richer | Ch. 12 (Device Flow), Ch. 6 (Client Types) |
| SSH Configuration | “SSH Mastery” by Michael W. Lucas | Ch. 6 (Agent Forwarding), Ch. 11 (SSH for Automation) |
| Headless Systems | “The Linux Programming Interface” by Michael Kerrisk | Ch. 62 (Terminals), Ch. 34 (Process Groups) |
| Secrets Management | “Building Secure and Reliable Systems” by Google | Ch. 9 (Secrets), Ch. 6 (Least Privilege) |
| CI/CD Integration | “Continuous Delivery” by Jez Humble | Ch. 14 (Advanced Version Control) |
Common Pitfalls & Debugging
Problem 1: “Device code flow times out before user authorizes”
- Why: 10-minute timeout is too short, or user didn’t see the prompt
- Fix: Send timeout reminder:
echo "⏰ 5 minutes remaining. Visit https://anthropic.com/device" - Quick test: Wait 11 minutes without authorizing, verify graceful timeout
Problem 2: “Token file is world-readable, exposing credentials”
- Why: Default file creation umask allows group/other read
- Fix: Force secure permissions:
(umask 077 && echo "$token" > ~/.kiro/credentials.json) - Quick test:
ls -l ~/.kiro/credentials.jsonshould show-rw-------
Problem 3: “Authentication works locally but fails in CI/CD”
- Why: CI runs as different user with no home directory
- Fix: Use environment variables in CI:
export KIRO_TOKEN="$KIRO_API_KEY" kiro auth login --token-stdin <<< "$KIRO_TOKEN" - Quick test: Unset
$HOMEand verify token is read from env
Problem 4: “SSH agent forwarding doesn’t work”
- Why:
ForwardAgentnot enabled or SSH key not added to agent - Fix:
# On local machine ssh-add ~/.ssh/id_rsa ssh-add -l # Verify key is added # In ~/.ssh/config Host dev-server ForwardAgent yes - Quick test: SSH to server, run
ssh-add -l, verify keys are listed
Problem 5: “Device flow polling hammers the OAuth server (rate limit)”
- Why: Polling every second instead of respecting
intervalfrom response - Fix: Use the
intervalfield from device code response:interval=$(echo "$response" | jq -r '.interval // 5') sleep $interval - Quick test: Monitor network requests, verify polling rate matches interval
Definition of Done
- Kiro detects headless environment automatically (no
$DISPLAY) - Device code flow is initiated when browser is unavailable
- User sees clear instructions: URL to visit and code to enter
- Polling respects the
intervalfrom OAuth response (no rate limiting) - Token is stored in
~/.kiro/credentials.jsonwith600permissions - Authentication timeout (10 minutes) is handled gracefully
- Token refresh is implemented for long-running sessions
- CI/CD integration works via environment variable (
KIRO_API_KEY) - SSH agent forwarding is documented as an alternative
- Installation script (
setup-headless-kiro.sh) is provided - Documentation explains how to troubleshoot headless auth failures