ConduitMcp.Client.OAuth.Loopback (ConduitMCP v0.11.0)

Copy Markdown View Source

Interactive authorization for CLI and desktop apps: a one-shot callback server on 127.0.0.1 (RFC 8252 §7.3 loopback redirect). Compiled only with :finch.

{:ok, tokens} =
  ConduitMcp.Client.OAuth.Loopback.run(:docs,
    open: fn url -> System.cmd("open", [url]) end,
    challenge: challenge
  )

run/2:

  1. starts Bandit on 127.0.0.1 (port 0 by default: any free port, which RFC 8252 lets the authorization server accept for loopback redirect URIs; give :port if yours needs a fixed one) serving exactly one request on :path;
  2. builds the authorization URL with redirect URI http://127.0.0.1:<port><path> (ConduitMcp.Client.OAuth.authorize_url/2);
  3. calls the host's :open function with the URL - the library never launches a browser itself: the host decides how (open, xdg-open, printing the URL);
  4. waits (:timeout, default 5 minutes) for the browser's redirect, answers it with a short page, and stops the server;
  5. completes the flow with ConduitMcp.Client.OAuth.handle_callback/3.

The server binds the loopback address only and answers a single callback (OA-11): any later request gets 410 Gone, and the listener is gone right after. The pending authorization never leaves the calling process, so state is used once by construction.

start/1 and await/2 are the two halves of step 1 and 4, for a host that runs the flow itself; await/2 returns the callback's query parameters.

Summary

Functions

Waits up to timeout ms for the callback, then stops the server. Returns the callback's query parameters, or {:error, :timeout}.

Runs a whole interactive authorization for client_or_config (see the moduledoc) and returns the stored tokens.

Starts the one-shot callback server.

Stops the callback server (idempotent).

Types

t()

@type t() :: %ConduitMcp.Client.OAuth.Loopback{
  redirect_uri: String.t(),
  ref: reference(),
  server: pid()
}

Functions

await(loopback, timeout \\ 300_000)

@spec await(t(), timeout()) :: {:ok, map()} | {:error, :timeout}

Waits up to timeout ms for the callback, then stops the server. Returns the callback's query parameters, or {:error, :timeout}.

run(client_or_config, opts)

Runs a whole interactive authorization for client_or_config (see the moduledoc) and returns the stored tokens.

Options

  • :open (required) - a one-arity function given the authorization URL.
  • :port, :path - see start/1.
  • :timeout - how long to wait for the user, default 5 minutes.
  • :challenge, :scopes, :principal - passed to ConduitMcp.Client.OAuth.authorize_url/2.

start(opts \\ [])

@spec start(keyword()) :: {:ok, t()} | {:error, term()}

Starts the one-shot callback server.

Options

  • :port - default 0 (any free port).
  • :path - the callback path, default "/callback".

stop(loopback)

@spec stop(t()) :: :ok

Stops the callback server (idempotent).