brama subscription login¶
Sign one provider account in and prove the repair. Who logs in is stated every time with --by: weles asks Weles to drive the account’s sign-in row and proves the result with Brama’s refresh path; hand prints the provider’s authorize page for you to open in your own browser, reads the code it shows on stdin, stores the grant and proves it with one minimal completion. One operation with two methods is one verb; nothing is assumed when --by is left out.
Invocation¶
brama subscription login <PROVIDER> --by weles --reason <REASON> [--subscription-id <ID>] [--login-item <LOGIN_ITEM>] [--json]
brama subscription login <PROVIDER> --by weles --subscription-id <ID> --reason <REASON> --gateway-consumer <CONSUMER> --bearer-role <ROLE> [--login-item <LOGIN_ITEM>] [--json]
brama subscription login <PROVIDER> --by hand --subscription-id <ID> --reason <REASON> [--gateway-consumer <CONSUMER> | --gateway <URL>] [--bearer-role <ROLE>] [--json]
| Input | Required/default | Meaning |
|---|---|---|
<PROVIDER> | required | One of codex, claude-code, or kimi. --by hand has a manual flow for claude-code only; the others are refused by name. |
--by weles|hand | required; no default | Who logs the account in: Weles through its sign-in row, or you in your own browser. |
--reason <REASON> | required | Nonempty audit reason recorded with the sign-in verdict. |
--subscription-id <ID> | Required by hand and for remote Weles sign-in. Local Weles sign-in may omit it only when exactly one active subscription matches. | The exact Brama subscription whose grant is replaced and proved. Automatic renewal always supplies it. |
--login-item <LOGIN_ITEM> | --by weles only; optional | An exact Skarbiec login reference. Otherwise the identity and login method are resolved from Skarbiec; no Weles account registration is required. |
--gateway-consumer <CONSUMER> | optional | Resolve the serving gateway through Stado. The gateway executes the selected method and stores its own grant; Weles runs on its selected host, not the workstation. |
--gateway <URL> | optional; not with --gateway-consumer | The same, with the serving gateway origin named directly. |
--bearer-role <ROLE> | required with a gateway | The Skarbiec role whose token authorizes the console. No bearer is placed in command arguments. |
| stdin | --by hand: required | One line: the code#state text or the whole redirect URL the page shows. The code is a credential, so it is never accepted as an argument. |
--json | optional; off | Print the verdict as JSON instead of labeled lines. |
By Weles¶
Output and state¶
Brama calls Weles's authenticated POST /reauth/resolve to resolve the exact Skarbiec identity without opening a browser. It passes account_revision to POST /reauth, checks the response and refreshes the persisted credential. The saved verdict includes the subscription, login reference, account and software revisions, Weles run_id and observed second_factor. A failure also retains its stage and HTTP status. The CLI, Desktop and automatic renewal share this implementation; automatic renewal does not require a separate sign-in command.
Codex provider requests use tokens.account_id when the stored grant names it, otherwise the chatgpt_account_id claim in tokens.id_token. An absent claim adds no account header. A malformed identity token, a wrong-typed tokens or OpenAI auth object, or a blank or wrong-typed account id is refused before OpenAI is contacted with credential_unauthorized and the damaged field. Sign the account in again through this flow instead of editing the grant. The CLI pool listing and Desktop Subscription Pool report the last recorded credential state, which need not include a refusal made before provider contact.
Brama Desktop's explicit Sign in action targets the selected account through POST /v1/admin/subscription-pool/sign-in with "by": "weles", POST /v1/admin/subscription-sign-in/:agent_id/:subscription_id, or POST /v1/account/subscription-sign-in/:subscription_id. The body names a nonempty reason and optional login_item; the pool route additionally requires subscription_id and by. Brama verifies ownership and derives the provider from that subscription. The sign-in runs until Weles reports how it ended. The app does not launch a local browser, and neither listing nor refreshing usage invokes this action.
Remote CLI sign-in uses the same pool API as Desktop. It verifies the requested member's provider before dispatch, prints each streamed progress event to stderr and prints the final exact-member verdict to stdout. Missing members and provider mismatches are refused before Weles runs. A lost, malformed or prematurely closed stream is unconfirmed, never successful, and is not retried automatically.
Second-factor challenges¶
Weles answers an offered authenticator challenge with the stored seed. Without a seed, it selects an offered Google phone approval and waits for Google's result. The run then waits for a person: weles runs list and weles runs show <run> show what it asked for (Runs waiting for a person), as does Weles Desktop's Running screen on the managed worker. Approve it on the account owner's phone; nothing else is needed when Google moves on. When the prompt never arrived or nothing moved after approving, weles runs answer <run> --not-received | --approved tells the run; weles runs cancel <run> --detail <why> ends the wait.
Only the structured google_2fa_material_missing refusal starts authenticator enrolment. Brama binds that attempt to the same resolved subscription and login, confirms the Weles run and Skarbiec seed readback, then signs that account in again and refreshes its credential. A failed enrolment remains a failed sign-in, with its actual cause; Brama does not loop or silently replace an existing authenticator.
In Brama Desktop, select an account and open Second factor to see the observed challenge, method, stored seed state and seed-read error. required: false means Google did not ask during that observed sign-in, not that the account has disabled two-factor authentication. A sign-in without challenge evidence remains unobserved.
Exact refusals¶
- Unsupported provider:
Weles does not support subscription authentication for <provider>. - Empty reason:
--reason must say why this sign-in is being run. - Missing admission credential: when
BRAMA_WELES_REAUTH_TOKENis unset, Brama reads the item playing rolebrama-weles-reauth; no such item is refused withno vault item carries stado:role:brama-weles-reauth, and two with the number of items that carry it. - Identity failures name the Skarbiec subscription and distinguish
subscription_identity_missing,skarbiec_login_missing, conflicting login material and a changed account revision. - Weles execution failures retain the actual
failure.code,stage, provider HTTP status andrun_id. An unreadable or lost execution response is unconfirmed, not proof that no browser ran. - Weles not answering:
weles_unreachable. Account resolution that gets no answer is refused withWeles did not answer POST <url>/reauth/resolve, so no sign-in was started: <transport error>; a sign-in request whose connection Weles never accepted records afailedverdict withWeles did not accept the connection for POST <url>/reauth, so no sign-in was started: <transport error>. <where Stado places Weles>,browser_started: false. Neither is held against the account: the next maintenance pass signs it in again by itself. - No authenticator seed in Skarbiec: when Weles stops at
google_2fa_material_missingand the enrolment it orders does not finish, the verdict opens withSkarbiec holds no authenticator seed on login <login> of subscription <id>, so Weles stopped at the provider's second factor (google_2fa_material_missing), followed by; enrolling an authenticator through Weles failed: <cause>(authenticator_enrolment_failed) or; the enrolment Weles ran did not leave a confirmed seed: <detail>(authenticator_enrolment_unconfirmed). Both carry the login asfailure.missing_seed_login. - A phone approval that Google does not complete reports
google_push_not_approved; a sign-in Google itself ends while the approval is awaited (a page underaccounts.google.com/info/, such assessionexpired) reportsgoogle_sign_in_ended_during_approvalwith that page and when the approval was asked. A method that cannot be selected reports its observed challenge rather than treating it as no second factor. - Enrolment preserves
authenticator_replacement_requires_consent,setup_confirmation_unobservedand vault-read errors. A failedtotp seedoperation is not evidence that a seed is missing. - A member whose latest recorded sign-in is a final failure (the provider refused the credential, or the attempt was not retryable) with the same account revision and the same sign-in executor is not driven again: the recorded verdict comes back with
replayed: true,replay_of_atnaming the instant it was recorded, and adetailthat opens withnot run: the failed attempt recorded at <instant> standsbefore the recorded detail.atandrun_idare the recorded attempt's, not this call's. A changed login row, a new Weles release, or the sign-in cooldown having passed lets the next call run. - A retained verdict with a missing, empty or non-string
atordetailrefuses replay:cannot replay sign-in for subscription <id>: recorded <field> is missing, empty or not a string; no browser was started. The CLI prints that cause and fails; Desktop receives the same cause as a refused sign-in event. Brama neither replaces missing evidence with invented text nor starts another provider attempt to conceal the invalid record.
An unconfirmed Weles response or a refresh that obtains nothing returns a failed verdict and exits 1; Brama never guesses between accounts.
By hand¶
No Weles host, worker credential or Skarbiec login row is involved. For claude-code the flow is the one omp auth-broker login anthropic runs, so the stored grant is the kind the automatic refresh keeps alive.
- Brama draws a PKCE verifier and a state and prints the provider’s authorize page. Nothing has been contacted yet.
- You open it in your own browser, sign into the account you want in the pool and approve; paste the
code#statethe page shows, or the whole redirect URL. - Brama checks the state is the one it drew, exchanges the code at the provider’s token endpoint and stores the grant as the subscription’s credential.
- Brama spends one minimal completion on the stored grant: a probe, not a refresh, so a grant shared with another holder is not rotated out from under it.
The verdict lists the provider, subscription, account, result and detail; --json prints the same fields as one object, and the exit status is zero only for result: signed_in. Without a gateway the command runs where Brama runs, because that is where the grant is stored. With --gateway-consumer (or --gateway) and --bearer-role the serving gateway does the two steps through POST /v1/admin/subscription-pool/sign-in with "by": "hand" and …/sign-in/:sign_in_id (HTTP API), as Brama Desktop’s Sign in by hand does.
Exact refusals¶
- Another provider:
a manual sign-in is defined for claude-code; `<provider>` is not it. No page is printed. - A host that holds no vault of its own, run without a gateway:
no sign-in was started: the grant could not be stored on this host (<Skarbiec's sentence>); name the gateway that serves the pool with --gateway-consumer <CONSUMER> --bearer-role <ROLE> (or --gateway <URL> --bearer-role <ROLE>) so it stores the grant in its own vault. - The gateway refusing either step:
the gateway refused to begin the sign-in: <status>: <its whole answer>orthe gateway refused to complete the sign-in: …; a gateway that holds the subscription under another provider:no sign-in was started: the gateway holds <id> as a <provider> subscription, not <PROVIDER>. - The paste:
nothing was pasted;paste the `code#state` the page shows, or the whole redirect URL;the pasted state is not the one this sign-in started with; open the URL again and paste what that page shows. - The provider:
the provider refused the code with HTTP <status>: <body>;the provider's answer carries no refresh token; Brama cannot keep a grant it cannot renew;the grant from the code the operator pasted is stored, but the provider would not serve it: <the provider's sentence>.
Flags that contradict the method¶
--by handwith--login-item:--login-item <LOGIN_ITEM> names a Weles sign-in row, and --by hand signs in through your own browser; drop it or sign in --by weles.--by handwithout--subscription-id:--by hand replaces one subscription's grant; name it with --subscription-id.- No
--by, a gateway without--bearer-role, or--bearer-rolewithout a gateway: clap refuses the arguments.
These are usage errors, refused before anything is contacted, with clap’s usage exit status.
A remote Weles request without --subscription-id reports remote Weles sign-in requires --subscription-id for the exact account and exits unsuccessfully without starting a browser.
See the command group or the CLI tree.