Authentication

Authentication

Voyager uses a two-layer authentication model: API keys identify the tenant, and the X-User-Id header selects which LinkedIn account to use within that tenant. Single-user tenants can omit the X-User-Id header and Voyager defaults to the only user.

Every Voyager response is wrapped in { success, statusCode, message, data, errors }. Access endpoint payloads as res.data.<field>. See Introduction.

Required Headers

Every request to Voyager must include:

HeaderValueDescription
AuthorizationBearer voy_xxxTenant-scoped API key
X-User-IdcharisLinkedIn account identifier within the tenant
$curl -H "Authorization: Bearer $KEY" \
> -H "X-User-Id: $USER" \
> "$BASE/api/profile/me"

API Keys

Tenant API keys use the voy_ prefix and are scoped to a single tenant. A tenant can have multiple keys for different environments or team members.

Create a key

$curl -X POST "$BASE/api/keys" \
> -H "Authorization: Bearer $KEY" \
> -H "X-User-Id: $USER" \
> -H "Content-Type: application/json" \
> -d '{"label": "production-agent"}'

Response:

1{
2 "success": true,
3 "key": "voy_a1b2c3d4e5f6...",
4 "label": "production-agent",
5 "hashPrefix": "a1b2c3d4"
6}

The full API key is only shown once at creation time. Store it securely. Voyager stores a SHA-256 hash, so the key cannot be recovered.

List keys

$curl "$BASE/api/keys" \
> -H "Authorization: Bearer $KEY" \
> -H "X-User-Id: $USER"

Revoke a key

$curl -X DELETE "$BASE/api/keys/a1b2c3d4" \
> -H "Authorization: Bearer $KEY" \
> -H "X-User-Id: $USER"

Admin Authentication

Admin endpoints (/api/admin/*) use a different authentication scheme. The ADMIN_SECRET environment variable is set at server startup, and requests authenticate with:

$curl -H "Authorization: Bearer YOUR_ADMIN_SECRET" \
> "$BASE/api/admin/tenants"

Admin routes manage tenants, users, session overrides, and system diagnostics. They are not scoped to a specific tenant.

Chrome Extension

The easiest way to sync your LinkedIn session is the Voyager Chrome Extension. It:

  1. Captures your li_at, JSESSIONID, and SalesNav cookies automatically
  2. Detects your LinkedIn country for proxy routing
  3. Sends cookies to Voyager via POST /api/session
  4. Shows session health status (green = valid, red = expired)
  5. Auto-syncs on a configurable interval

Install the extension from chrome://extensions (developer mode) by loading the extension/ directory.

The extension captures both LinkedIn and SalesNav cookies. When li_a is detected, the export button shows ”(+ SalesNav)” to confirm SalesNav access will be synced.

Session Lifecycle

  1. SyncPOST /api/session with cookies and userAgent
  2. Validate — Voyager probes LinkedIn and returns sessionValid: true/false
  3. Use — Make API calls; Voyager uses the synced session
  4. Monitor — Background polling detects expired sessions and emits session_expired webhook
  5. Re-sync — When cookies expire, sync fresh cookies from the extension

You can re-sync cookies at any time without downtime. Voyager replaces stored cookies atomically and invalidates per-request caches (CSRF, mailbox URN) that depend on the old session. In-flight requests complete against the old cookies; the next request picks up the new ones.

Security Best Practices

  • Rotate API keys periodically
  • Use separate keys for development and production
  • Set up session_expired webhooks so your agent can alert when re-authentication is needed
  • Never commit API keys to source control
  • The ADMIN_SECRET should be a strong random string (64+ hex characters)