Skip to content

Getting Access

WarmHub handles sign-up and sign-in through a hosted login flow — there are no credentials to configure locally. The first time you sign in, your account is created automatically.

There is no separate registration step. The first time you log in (via the CLI or web app), WarmHub creates your account. Supported sign-in methods include:

  • Email and password
  • Google
  • GitHub
  • SSO (SAML/OIDC) — if configured for your organization

Your identity works across the CLI, web app, SDK, and HTTP API.

Org invites are sent to a specific email address. Sign in with an account that uses that same address — otherwise you land in a different account than the one that was invited.

  • Signing in with GitHub uses the primary email on your GitHub account. If that primary email doesn’t match the invited address, GitHub sign-in authenticates as the wrong identity, and GitHub offers no way to pick a different email for sign-in. When the invited address isn’t your GitHub primary, sign in with email and password instead.
  • Each account is tied to a single email today. A personal email and a work email are separate accounts — there’s no way to consolidate them. Keep them distinct and sign in with the email that matches the org you’re joining.

First-time sign-in also provisions a personal org for you automatically — a namespace you own where you can create repos immediately without waiting to be added to a team org. WarmHub picks the slug as follows:

  1. GitHub login — if you signed in with GitHub (or your identity exposes a GitHub login), WarmHub prefers that login as your personal org slug.
  2. Adoption — if you already own an org whose name matches your GitHub login, WarmHub adopts it as your personal org rather than creating a duplicate.
  3. Suffixing — if the preferred slug is taken by someone else, WarmHub appends a numeric suffix (alice-2, alice-3, …).
  4. Fallback — if no usable login is available, the slug falls back to user-<id> derived from your user ID.

Personal orgs are regular orgs in every other respect — you own them, you can create repos and invite members, and they appear in wh org list. Two constraints apply:

  • Rename. Personal orgs linked to a GitHub login (including fallback slugs) can’t be renamed with wh org rename. Personal orgs without a linked GitHub login (SSO or email-only) can be renamed normally.
  • Reserved names. The following slugs are reserved and rejected on create and rename (case-insensitive): admin, api, billing, blog, docs, help, login, public, settings, signup, status, support, system, warmhub, www. This applies to all orgs, not just personal ones.

When you sign in, WarmHub publishes a public identity for you — the identity your commits are attributed to, and the one other records point at when they name you as an author. It shows a display name derived from your account and never includes your email address.

Behind that, the identity is a record named Identity/<your-id> in the globally readable warmhub/users repo, so it’s visible in the graph and can be referenced from anywhere. It’s published the first time you sign in and refreshed periodically; publishing is best-effort, so a delay never blocks sign-in or any write.

Terminal window
wh auth login

This opens your browser for a device authorization flow:

  1. The CLI displays a verification URL and one-time code.
  2. Your browser opens to the login page.
  3. You authenticate and confirm the code.
  4. The CLI receives a token and saves it to ~/.warmhub/auth.json.

Tokens auto-refresh in the background for active device-flow sessions. You should only need to log in once per machine.

If your session is invalidated (for example, revoked server-side or an expired refresh token), the CLI surfaces a Session expired error and prompts you to run wh auth login again.

Non-interactive environments (CI, containers, headless servers):

For automation, use a personal access token via the WH_TOKEN environment variable instead of interactive login. See the wh token commands for creating tokens.

If you need to pipe a raw JWT (e.g., from another auth system):

Terminal window
echo "$JWT" | wh auth login --with-token

Piped tokens cannot auto-refresh — you’ll need to provide a new one when it expires. PATs are the preferred approach for most non-interactive use cases.

You can manage multiple credential sets with the --profile (-P) flag. Each profile stores its own tokens and the API endpoint used at login time.

Terminal window
# Log in with a named profile (e.g., for a separate account)
wh auth login --profile work
wh auth login --profile personal
# Use a profile for any command
wh thing list --repo myorg/myrepo --profile work
# Or set via environment variable
export WH_PROFILE=work
wh thing list --repo myorg/myrepo

Without --profile or WH_PROFILE, all commands use the default profile. Each profile remembers the API URL it was logged in with — that stored URL applies when the profile is active, unless you override it with --api-url. The WARMHUB_API_URL environment variable is the fallback when no profile is loaded (for example, on a fresh machine before login).

Terminal window
wh auth status

Shows all profiles with their identity, auth method (device flow, piped token, or WH_TOKEN environment variable), token expiry, and API endpoint. Use --profile <name> to check a specific profile.

Terminal window
wh auth logout

Removes the default profile’s saved tokens from ~/.warmhub/auth.json. Use --profile <name> to log out a specific profile. Other profiles are not affected. If WH_TOKEN is set as an environment variable, unset it separately.

For scripts and automation, set WH_TOKEN to a personal access token or JWT:

Terminal window
export WH_TOKEN=eyJhbGciOi...
wh thing list # authenticates automatically

WH_TOKEN takes precedence over saved credentials from wh auth login. The CLI checks for it on every command.

All API requests authenticate via Bearer tokens in the Authorization header. WarmHub supports three token types:

TypeObtained viaUse caseExpires
Session JWTwh auth login or web app sign-inInteractive useShort-lived (auto-refreshes)
Personal access tokenwh token create or SDK client.token.createScripts, CI/CD, integrations30 days default, 1 year max
MCP OAuth tokenAutomatic (OAuth flow in MCP client)MCP clients (Claude, Cursor, etc.)Session-based

All token types share a unified validation model — they go through the same server-side JWT verification and permission checking.

See Personal Access Tokens for creating and managing PATs.

Repositories are either public or private. Visibility is set at creation time and can be changed by org administrators.

PublicPrivate
Read (queries, HEAD, history)Anyone — no auth requiredAuthenticated, repo:read permission
Write (commits, shape mutations)Authenticated, repo:write permissionAuthenticated, repo:write permission
Manage (subscriptions, credentials)Authenticated, repo:configure permissionAuthenticated, repo:configure permission
Anonymous read requestsReturn data normallyReturn 404

All writes require authentication regardless of visibility. Private reads require repo:read permission on the target repo — sign-in alone is not enough; you need to be a member of the repo’s org. PATs can narrow what a member is allowed to access, but they don’t grant access on their own. Cross-repo reads to a private target apply the same check, so a canonical wh:org/repo/... wref only resolves when you can read the target repo.

The anonymous-access row covers ordinary reads (queries, HEAD, history). Some endpoints require management-level access even on a public repo: action observability (run history, attempts, live feed, notifications) needs repo:configure, so anonymous callers get an opaque 404 rather than data. See Actions API for the full contract.