Signing in to a subscription (:anthropic, :openai_codex): the OAuth
flow (Rho.Auth.OAuthFlow) with the provider's own localhost redirect,
answered by this BEAM.
begin/1 starts a :gen_tcp listener on 127.0.0.1 at the redirect's
port (54545 for Anthropic, 1455 for OpenAI: the redirects omp registers),
opens the authorize URL in the device's browser, and when the browser is
sent back to http://localhost:<port>/…?code=…&state=… exchanges the code,
stores the credentials (Rho.Auth.put/2, which tells its
subscribers) and sends whoever called begin/1
{:rho_login, provider, :ok | {:error, message}}.
Anthropic's authorize page may show the code (code#state) instead of
redirecting; paste/2 takes it (or the whole redirect URL) for the flow
in progress. One flow at a time: begin/1 replaces an unfinished one,
and cancels an exchange still running for an older one (its result is
never used). A redirect carrying another flow's state (an old tab) gets
an error page and leaves the flow in progress alone; the flow ends on its
own redirect, a paste, or after 15 minutes without either.
The exchange runs in a worker and retries transport errors every 2 s for up to 9 minutes: Android blocks a backgrounded app's network (~60 s after it leaves the foreground), so it completes when the user switches back from the browser.
Options: :open_url (fn url -> :ok end; default
Rho.Config.open_url/1, which a mob app points at Mob.Device.open_url/1),
:redirect (fn provider -> uri end, default the provider's), :respond
(tests: Rho.Auth.OAuthFlow), :flow_timeout_ms.
Summary
Functions
Starts a sign-in and opens the browser; returns the URL that was opened.
{:error, :not_oauth} for a provider that takes only an API key.
Returns a specification to start this module under a supervisor.
The host default for config :rho, :open_url: the computer's browser
(open on macOS, xdg-open elsewhere on Unix, start on Windows),
started without waiting for it. When there's none it logs that and
still returns :ok: begin/1 returns the URL for the host to show.
Finishes the flow in progress with what the provider's page showed: a
code#state, a bare code, or the redirect URL.
The provider of the sign-in in progress (nil when none), whose result goes to the caller from now on: a page reopened during the browser flow takes it over from the one that started it.
Started by Rho.Supervisor (its :login option holds opts, see the moduledoc).
Functions
@spec begin(Rho.Auth.provider()) :: {:ok, String.t()} | {:error, term()}
Starts a sign-in and opens the browser; returns the URL that was opened.
{:error, :not_oauth} for a provider that takes only an API key.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec open_in_browser(String.t()) :: :ok
The host default for config :rho, :open_url: the computer's browser
(open on macOS, xdg-open elsewhere on Unix, start on Windows),
started without waiting for it. When there's none it logs that and
still returns :ok: begin/1 returns the URL for the host to show.
@spec paste(Rho.Auth.provider(), String.t()) :: :ok | {:error, :no_login_started | :no_code | :state_mismatch | {:started_for, atom()}}
Finishes the flow in progress with what the provider's page showed: a
code#state, a bare code, or the redirect URL.
@spec pending() :: Rho.Auth.provider() | nil
The provider of the sign-in in progress (nil when none), whose result goes to the caller from now on: a page reopened during the browser flow takes it over from the one that started it.
@spec start_link(keyword()) :: GenServer.on_start()
Started by Rho.Supervisor (its :login option holds opts, see the moduledoc).