Skip to main content
Auth events track OAuth authentication flows and state changes. In RPC mode, loaf does not auto-open browsers—your client must handle URLs and display device codes.

auth.flow.started

Emitted when an OAuth flow begins.
{
  "type": "auth.flow.started",
  "timestamp": "2026-01-01T00:00:00.000Z",
  "payload": {
    "provider": "openai",
    "flow_type": "browser"
  }
}
payload.provider
string
Provider name: "openai" or "antigravity"
payload.flow_type
string
Flow type: "browser" (OAuth redirect) or "device_code" (headless)

auth.flow.url

Emitted when a browser URL is ready for the user to open.
{
  "type": "auth.flow.url",
  "timestamp": "2026-01-01T00:00:00.000Z",
  "payload": {
    "provider": "openai",
    "url": "https://auth.openai.com/authorize?client_id=...",
    "expires_at": "2026-01-01T00:05:00.000Z"
  }
}
payload.url
string
Full OAuth authorization URL. Your client must display this URL to the user.
payload.expires_at
string
ISO 8601 timestamp when the URL expires (typically 5 minutes)
In RPC mode, loaf does NOT auto-open browsers. You must display this URL and instruct the user to open it.

auth.flow.device_code

Emitted for device code OAuth flows (headless/CI environments).
{
  "type": "auth.flow.device_code",
  "timestamp": "2026-01-01T00:00:00.000Z",
  "payload": {
    "provider": "openai",
    "user_code": "ABCD-EFGH",
    "verification_url": "https://auth.openai.com/device",
    "expires_in": 900
  }
}
payload.user_code
string
Short code the user must enter on the verification URL
payload.verification_url
string
URL where the user enters the device code
payload.expires_in
number
Seconds until the device code expires (typically 900 = 15 minutes)

Device code flow example

if (event.type === 'auth.flow.device_code') {
  console.log('\nAuthentication Required:');
  console.log(`1. Visit: ${event.payload.verification_url}`);
  console.log(`2. Enter code: ${event.payload.user_code}`);
  console.log(`3. Expires in ${event.payload.expires_in} seconds\n`);
}

auth.flow.completed

Emitted when OAuth succeeds and credentials are stored.
{
  "type": "auth.flow.completed",
  "timestamp": "2026-01-01T00:00:00.000Z",
  "payload": {
    "provider": "openai",
    "profile": {
      "email": "[email protected]",
      "name": "User Name"
    }
  }
}
payload.profile
object
User profile information from the provider (when available)

auth.flow.failed

Emitted when OAuth fails.
{
  "type": "auth.flow.failed",
  "timestamp": "2026-01-01T00:00:00.000Z",
  "payload": {
    "provider": "openai",
    "error": "User canceled authentication",
    "code": "user_canceled"
  }
}
payload.error
string
Human-readable error message
payload.code
string
Error code: "user_canceled", "timeout", "network_error", etc.

state.changed

Emitted when global authentication state changes (provider added/removed).
{
  "type": "state.changed",
  "timestamp": "2026-01-01T00:00:00.000Z",
  "payload": {
    "change_type": "auth_updated",
    "providers": ["openai", "openrouter"]
  }
}
payload.change_type
string
Type of change: "auth_updated", "model_changed", "config_changed"
payload.providers
array
List of currently authenticated provider names

OAuth flow sequences

Browser flow (desktop)

  1. auth.flow.started - Flow begins
  2. auth.flow.url - URL available
  3. User opens URL in browser and approves
  4. auth.flow.completed - Success
  5. state.changed - Auth state updated

Device code flow (headless)

  1. auth.flow.started - Flow begins with flow_type: "device_code"
  2. auth.flow.device_code - Device code available
  3. User visits verification URL and enters code
  4. loaf polls for completion (no intermediate events)
  5. auth.flow.completed - Success
  6. state.changed - Auth state updated

Failure flow

  1. auth.flow.started - Flow begins
  2. auth.flow.url or auth.flow.device_code - Auth details provided
  3. User cancels or timeout occurs
  4. auth.flow.failed - Failure event

Handling timeouts

Browser URLs expire after 5 minutes. Device codes expire after 15 minutes. If the user doesn’t complete authentication in time, you’ll receive auth.flow.failed with code: "timeout".

API key authentication

API key setup (OpenRouter, Exa) does not emit events—use the synchronous auth.set.openrouter_key and auth.set.exa_key methods instead.

Build docs developers (and LLMs) love