Headless, resumable OAuth for registered providers — the daemon-side engine
behind POST /v1/providers/:id/auth/{start,complete,poll}.
WHY THIS EXISTS. :provider/auth-fn is interactive: it prints prompts and
blocks on read-line or a Lanterna dialog. That works only when the client
IS the daemon's own terminal, which is exactly why the TUI reaches PAST the
gateway and calls provider-anthropic/login! in-process. A phone, a browser
tab, or any remote client cannot do that.
This namespace splits the same flows into steps that survive a request boundary, keyed by a short-lived server-side flow id:
start -> mints a flow, returns what the USER must see (URL, user code) complete -> PKCE: exchange the pasted redirect URL (Anthropic, Codex) poll -> device: read the background await's verdict (GitHub Copilot)
SECURITY BOUNDARY. The provider's :flow value (PKCE verifier, CSRF state,
device code) stays in this atom and is NEVER emitted. Credentials are
written by the provider extension into the daemon's own auth file, exactly
as the interactive path does — no token, verifier, or refresh token is ever
serialized to a client. public-view is an allowlist, not a redaction pass.
Headless, resumable OAuth for registered providers — the daemon-side engine
behind `POST /v1/providers/:id/auth/{start,complete,poll}`.
WHY THIS EXISTS. `:provider/auth-fn` is interactive: it prints prompts and
blocks on `read-line` or a Lanterna dialog. That works only when the client
IS the daemon's own terminal, which is exactly why the TUI reaches PAST the
gateway and calls `provider-anthropic/login!` in-process. A phone, a browser
tab, or any remote client cannot do that.
This namespace splits the same flows into steps that survive a request
boundary, keyed by a short-lived server-side flow id:
start -> mints a flow, returns what the USER must see (URL, user code)
complete -> PKCE: exchange the pasted redirect URL (Anthropic, Codex)
poll -> device: read the background await's verdict (GitHub Copilot)
SECURITY BOUNDARY. The provider's `:flow` value (PKCE verifier, CSRF state,
device code) stays in this atom and is NEVER emitted. Credentials are
written by the provider extension into the daemon's own auth file, exactly
as the interactive path does — no token, verifier, or refresh token is ever
serialized to a client. `public-view` is an allowlist, not a redaction pass.(cancel-auth! flow-id)Forget a flow the user abandoned AND stop its background device poll, so an abandoned sign-in stops talking to the provider immediately. Idempotent.
Forget a flow the user abandoned AND stop its background device poll, so an abandoned sign-in stops talking to the provider immediately. Idempotent.
(complete-auth! flow-id input)Finish a flow the client cannot finish on its own: pkce takes the redirect
URL (or bare code#state) the user pasted back, api-key takes the key the
user typed and the DAEMON persists it into its own config. The flow is
CLAIMED before the exchange runs, so a captured or double-submitted id cannot
spend it twice; a failed exchange puts it back so a mistyped paste is
retryable. Returns {:ok? true :status "ok"} or an error map.
Finish a flow the client cannot finish on its own: `pkce` takes the redirect
URL (or bare `code#state`) the user pasted back, `api-key` takes the key the
user typed and the DAEMON persists it into its own config. The flow is
CLAIMED before the exchange runs, so a captured or double-submitted id cannot
spend it twice; a failed exchange puts it back so a mistyped paste is
retryable. Returns `{:ok? true :status "ok"}` or an error map.(logout! provider-id)Clear provider-id's persisted credentials through its registered logout,
then invalidate the cached fleet so status flips on the next read.
Clear `provider-id`'s persisted credentials through its registered logout, then invalidate the cached fleet so status flips on the next read.
(poll-auth! flow-id)Read a device flow's verdict without blocking: pending, ok, error, or
expired. Consumes the flow once it settles.
Read a device flow's verdict without blocking: `pending`, `ok`, `error`, or `expired`. Consumes the flow once it settles.
(start-auth! provider-id)Begin headless auth for provider-id. Returns {:ok? true :flow {…}} with
the public flow view, or {:ok? false :error kw :message str}.
THREE kinds, ONE wire shape, so a client never special-cases a provider:
pkce stops here until complete-auth!, device already has a background
await running by the time this returns, and api-key asks the client to
collect a key and hand it back to complete-auth! — even plain key providers
are persisted BY THE DAEMON, never by the calling process.
Begin headless auth for `provider-id`. Returns `{:ok? true :flow {…}}` with
the public flow view, or `{:ok? false :error kw :message str}`.
THREE kinds, ONE wire shape, so a client never special-cases a provider:
`pkce` stops here until `complete-auth!`, `device` already has a background
await running by the time this returns, and `api-key` asks the client to
collect a key and hand it back to `complete-auth!` — even plain key providers
are persisted BY THE DAEMON, never by the calling process.(supported? provider-id)True when provider-id can be authenticated over the wire — OAuth (PKCE or
device) or a plain API key — as opposed to only through the interactive
terminal :provider/auth-fn.
True when `provider-id` can be authenticated over the wire — OAuth (PKCE or device) or a plain API key — as opposed to only through the interactive terminal `:provider/auth-fn`.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |