Skip to content

Authentication

A caller outside the web app, such as the CLI or another app you sign in to with your LangAlpha account, authenticates by sending a token in the Authorization header:

Authorization: Bearer <token>

The CLI’s browser sign-in is how you get one.

Credential Looks like Who uses it
Access token from a browser sign-in An OAuth access token The CLI after langalpha login, and other apps you sign in to with your LangAlpha account.
A computer’s token lac1.... The CLI inside a computer, for the agent’s commands.
The web app’s sign-in A session token The web app itself.

The server tells them apart by their form, and a token it refuses is refused outright, never retried as another kind.

A token reaches only the routes that declare a scope it holds:

Scope What it covers
agent:read Reading threads, their turns and streams, workspaces, computers, automations, and your model list.
agent:run Starting, steering, answering, retrying and cancelling turns, and running an automation now.
workspace:write Creating, changing, archiving and deleting workspaces and automations, and archiving and deleting threads.
computer:write Adding, starting, stopping, changing and removing computers.
data:read Market data, news, calendars, your portfolio and watchlists.

Routes that declare no scope answer only to the web app’s sign-in, whatever token you send. That keeps brokerage orders, secrets, publishing and your account identity out of any token’s reach. An order waiting for approval is answered only in the app, and a token that tries gets a 403 with type order_decision_forbidden.

Status Body or header What to do
401 WWW-Authenticate: Bearer error="invalid_token" The token is unknown, expired or revoked. Sign in again.
403 detail.type is insufficient_scope, with the scopes the route needs Use a token that holds them.
403 detail.type is forbidden_for_token The action is closed to this kind of token, such as a delete with a computer’s token.
503 Retry-After The server cannot check the token right now. Retry after the time given.

GET /api/v1/auth/principal answers who the server takes the caller for. Every token reaches it, whatever its scopes.

Field Meaning
user_id Your user id.
auth How you authenticated: session, oauth, computer or service.
client_id The app a browser sign-in token was issued to.
scopes What the token may do. Empty for a session, which needs none.
computer_id The computer, for a computer’s token.

GET /api/v1/auth/cli is public: a client calls it before it holds any credential, and the CLI’s login does exactly that.

Field Meaning
auth_required false on a server that asks for no credential.
issuer The sign-in provider to use for a browser sign-in, whose discovery document sits beside it. null when the server takes no browser sign-in.
client_id The public client a CLI signs in as. null with issuer.
scopes The scopes to ask the provider for, besides who the user is. Empty where the server grants scopes from your account rather than reading them from the token.

A default self-hosted install answers with these fields:

{
"auth_required": false,
"issuer": null,
"client_id": null,
"scopes": ["agent:read", "agent:run", "workspace:write", "computer:write", "data:read"]
}