Skip to content

Authentication API

POST /api/auth/portal-session agent
Create a portal session for a friend and return the portal URL. This is the primary way agents grant portal access.

Body:

{
"friend_id": "alice",
"agent": "my-agent"
}

The agent field is optional and defaults to the current agent.

Response:

{
"portal_url": "https://my-agent.your-domain.net/portal?s=abc123...",
"session_token": "abc123...",
"expires_at": "2026-04-01T12:00:00.000Z",
"expires_in": 2592000
}
POST /api/auth/magic-link agent
Legacy endpoint — creates a session and returns a portal URL. Uses the Host header to determine the agent.

Body:

{"friend_id": "alice"}

Response:

{
"portal_url": "https://my-agent.your-domain.net/portal?s=abc123...",
"session_token": "abc123...",
"link": "/portal?s=abc123...",
"expires_in": 2592000
}
GET /api/auth/verify/:token public
Verify a session token and redirect to the portal. Used when friends click magic links.

Parameters:

  • token (path) — Session token from magic link

Behavior:

  • If valid: redirects to https://<agent>.your-domain.net/portal?s=<token>
  • If expired/invalid: returns 401 {"error": "Link expired or invalid"}
GET /api/auth/me friend
Get the current friend's profile based on their session token.

Response:

{
"id": "alice",
"display_name": "Alice",
"preferred_channel": "signal",
"namespace": "friend-alice"
}
  • Sessions are stored in the sessions SQLite table
  • Default TTL: 30 days
  • Token format: nanoid (32 characters)
  • Expired sessions are cleaned up on each /api/health call
  • Sessions persist across controller restarts (SQLite-backed)