Key Design
Device Auth Flow
The CLI uses OAuth 2.0 Device Authorization Grant (RFC 8628) for login. This allows authentication on headless machines (SSH, containers) where a browser isn't directly available.
Flow
CLI vuer-auth DreamLake Server
│ │ │
├─ 1. POST /api/device/start ─→│ │
│ { device_secret_hash, │ │
│ client_id, scope } │ │
│←── { user_code, │ │
│ verification_uri, │ │
│ verification_uri_complete, │
│ expires_in, interval } │ │
│ │ │
├─ 2. Open browser ───────────→│ (user approves) │
│ or display QR code + URL │ │
│ │ │
├─ 3. Poll /api/device/poll ──→│ │
│ (every 5s, up to 10 min) │ │
│←── { access_token } │ │
│ │ │
├─ 4. POST /auth/exchange ────────────────────────────────→│
│ Authorization: Bearer {vuer-auth-token} │
│←── { dreamlake_token } ─────────────────────────────────│
│ │ │
└─ 5. Store token locally │Step by Step
1. Start Device Flow
CLI generates (or loads) a device secret, then requests a device code from vuer-auth:
POST https://auth.vuer.ai/api/device/start
{
"device_secret_hash": "sha256 of device secret",
"client_id": "dreamlake-client",
"scope": "openid profile email"
}Returns a user code and verification URL.
2. User Approval
The CLI opens the browser to the verification URL. If --no-browser is set, it displays:
- The verification URL
- A user code to enter manually
- An ASCII QR code for mobile scanning
3. Poll for Completion
CLI polls vuer-auth every 5 seconds (up to 120 attempts = 10 minutes):
POST https://auth.vuer.ai/api/device/poll| Response | Action |
|---|---|
200 + access_token | Success — proceed to exchange |
authorization_pending | Wait 5s, retry |
slow_down | Wait 10s, retry |
expired_token | Abort — code expired |
access_denied | Abort — user denied |
4. Token Exchange
The vuer-auth token is short-lived. CLI exchanges it for a long-lived dreamlake token:
POST http://localhost:10334/auth/exchange
Authorization: Bearer <vuer-auth-token>DreamLake Server verifies the vuer-auth token via JWKS, creates the user + namespace if needed, and returns a permanent dreamlake JWT.
5. Token Storage
The dreamlake token is stored locally using the best available backend:
| Backend | Location | Priority |
|---|---|---|
| System keyring | macOS Keychain / Windows Credential Manager / Linux Secret Service | 1st (most secure) |
| Encrypted file | ~/.dreamlake/tokens.encrypted (Fernet encryption) | 2nd |
| Plaintext file | ~/.dreamlake/tokens.json (0600 permissions) | 3rd (fallback, shows warning) |
The encryption key for the encrypted file backend is stored at ~/.dreamlake/encryption.key (0600 permissions).
Local Files
| File | Purpose |
|---|---|
~/.dreamlake/config.json | Device secret (persistent across logins) |
~/.dreamlake/tokens.encrypted | Encrypted dreamlake JWT |
~/.dreamlake/encryption.key | Fernet key for token encryption |
~/.dreamlake/uploads/{hash}.json | Resumable upload state (separate from auth) |
Configuration
| Env Var | Default | Description |
|---|---|---|
VUER_AUTH_URL | https://auth.vuer.ai | vuer-auth server URL |
DREAMLAKE_API_KEY | — | Skip login entirely — use this token directly |
Security Notes
- The device secret is generated once per machine (64 hex chars, 256 bits entropy) and persisted in
~/.dreamlake/config.json. It ties the device to the user's auth session. - The dreamlake JWT has no expiry — it's a long-lived token. Revocation is done by rotating the server's JWT secret.
dreamlake logoutremoves the stored token but does not revoke it server-side.