Repository navigation
feat: browser sign-in for pgedge starfleet - #73
Draft
AntTheLimey wants to merge 10 commits into
Draft
AntTheLimey wants to merge 10 commits into
AntTheLimey wants to merge 10 commits into
Conversation
AntTheLimey
force-pushed
the
feat/browser-login
branch
from
October 19, 2026 22:01
27c36bf to
4029529
Compare
Browser sign-in needs three building blocks below the commands: the public Auth0 settings per API (domain, audience, client ID, in one table), a reader for the tenant claims in a user's access token, and a profile marker for a browser session with its tenant. A session token's cache binding covers the API URL and the user under its own domain, so neither kind of token can pass for the other. Both client IDs are empty until the Auth0 app is applied, which makes browser sign-in report that it is not available yet.
internal/starfleet/signin runs the authorization-code flow with PKCE against Auth0: a loopback listener on the first free port of 8484, 8485 and 8486, a random state checked on return, an S256 challenge over a 32-byte verifier, and the code exchange at /oauth/token. The browser opener, the Auth0 base URL, the port list and the wait are injected, so the tests drive the callback with real requests and never open a browser or reach the network.
A profile marked as a browser session resolves to the user's cached token instead of a client-credentials exchange. Every request of a session carries X-pgEdge-Selected-Tenant: the profile's tenant, or the new persistent --tenant flag for one command, checked locally against the token's pgedge_tenant_ids. An API client never sends the header, and --tenant with one is a usage error. A session is never re-minted. An expired, missing or other-API token fails with exit 5 and names the login command, including when a long --wait outlives it. doctor's Auth and Tenant rows understand a session and report its selected tenant. conn.Resolve now takes conn.Flags, and conn.ReadFlags replaces the three copies of the persistent-flag reader.
auth login with no credential flags now signs the user in through the browser and saves the profile as a session: api_url, auth and tenant_id, with any API client ID and keychain secret removed. The token goes to the existing cache, bound to the API URL and the user, with its real expiry. A user in several tenants picks one at a prompt on a terminal, or gets the account default with a note on stderr; --tenant takes an ID or a name. --api-client keeps the old prompt for an ID and secret, and --client-id/--client-secret are unchanged. status, whoami and logout understand a session. whoami reports the user and the selected tenant without listing API clients, and status exits 5 for an expired session, which nothing can renew.
The guides, the starfleet reference and the pgedge-starfleet skill now present browser sign-in as the default and an API client as the path for CI, scripts and agents, with the session's tenant, --tenant, and the exit 5 an expired session gives. The command reference is regenerated for the new flags.
--debug printed the ID token from the sign-in exchange's response and the authorization code and PKCE verifier from its form-encoded request. id_token joins the secret field names, and a form-encoded request body now has the values of code, code_verifier and every secret field masked.
Any web page could end a sign-in by loading the loopback callback with a wrong state. Such a request now gets a 400 and the sign-in keeps waiting for the real one until its timeout. The token exchange always gets its HTTP client from the caller, so the unreachable fallback client is gone and the starfleet client site count returns to 4. The redirect URI is built in one place and tested against the three registered callbacks.
- Flag credentials over a browser-session profile no longer write their token over the session's cache; they resolve ephemerally, as the env pair does. - A profile tenant_id the token no longer reaches is exit 2, naming auth login --tenant, instead of silently acting in another tenant. whoami and doctor report the tenant requests actually carry. - auth status and doctor validate --tenant as resource commands do, and refuse it with an API client. - doctor -o json reports an expired session as unauthenticated with the expired message, matching auth status. - Browser login saves the profile before deleting an API client's keychain secret, so a failed save keeps a working profile. The wait-past-expiry test moves an injected clock instead of sleeping, and new tests cover the CLI-side PKCE pairing and --debug output during a sign-in.
The invite refusal, its help and the reference said every CLI credential is a client ID and secret, which browser sign-in made false. They now say an API client is refused by the API and the CLI does not send these requests for a browser sign-in either, without promising invite support. TestInviteGuardPremiseStillHolds now also runs both guarded verbs with a browser session and fails if either stops refusing, naming the follow-up that would change it.
Keep the tests that guard what a dev-tenant run would not reveal: state and PKCE checks, the registered callback URIs, the tenant header for sessions only, --debug redaction, flags over a saved session, the API URL binding, the secret kept on a failed save and the exit 5 expiry contract. Drop the tests of output wording, prompt flow, duplicate variants and happy paths, and fold the timeout and cancel cases into one table.
AntTheLimey
force-pushed
the
feat/browser-login
branch
from
October 19, 2026 22:59
4029529 to
e69baf0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
pgedge starfleet auth loginwith no credential flags signs in through the browser. It uses Auth0 authorization code with PKCE (S256) and a127.0.0.1loopback on 8484-8486. The CLI then calls the API as the user, with the user's access token in the 0600 token cache. Nothing is created server-side.--client-id/--client-secret, the env pair, and profiles holding a client.--api-clientbrings back the interactive ID and secret prompt.X-pgEdge-Selected-Tenanton every request. Login asks which tenant when there are several (on a TTY), or takes--tenant.--tenanton any starfleet command switches tenant for that command, validated against the token'spgedge_tenant_ids. API clients never send the header, and--tenantwith one is a usage error.pgedge starfleet auth login", never a silent re-mint.auth status,whoami,doctorandlogoutunderstand sessions.internal/apidefaults/auth0.go. Both client IDs are empty until saas#2040 is applied, so browser sign-in reports "not available for this API" until then.llmspages, the starfleet skill and the invite text now cover both sign-in kinds.Checks
make testpasses, with coverage at 90.5%.make lint,make docs-checkandmake lint-docsare clean.statecheck--client-idon a session profile overwrote the session.--debugprinted the ID token. It is now redacted, along with the form-encodedcodeandcode_verifier.--tenantchecks are fixed instatusanddoctor.stderrArgSiteswent from 200 to 211, for the new sign-in messages.Risks
auth loginfails on both APIs while the docs say it opens the browser. Nothing has run against real Auth0 yet. The dev end-to-end test comes after saas#2040 is applied to dev.auth statusexits 5 for an expired or missing session, where API clients exit 0. A session can't renew itself.--insecure-storagewithout an API client is now a usage error.invite create/acceptfor sessions are follow-ups.