Skip to main content

Auth

Three questions, answered separately.

QuestionAnswered by
Who are you?An identity provider — Entra or Google — or an API key
What is your session?A JWT, minted by the identity API
What may you do?The permissions carried on that JWT, checked per endpoint

The login flow

A person signing in:

Browser Auth UI Account API Identity API
│ │ │ │
│─── GET / ───────────▶│ │ │
│ │─ GET /organizations/{id}/signin ──▶ │
│◀── branded page ─────│◀─ name, logo, CSS, providers ──── │ │
│ │ │ │
│─── choose provider ─▶│ │ │
│◀────────── redirect to Entra / Google ────────────────── │
│─── returns with provider identity ─────────▶│ │
│ │─ POST /users/provision ──────────▶│ │
│ │◀─ account + permissions ──────────│ │
│ │─ POST /generatejwt ─────────────────────────▶│
│ │◀─ signed JWT ───────────────────────────────│
│◀── x-tagshape-auth cookie ─┤ │ │

Four of those calls are anonymous by necessity — they exist to establish an identity that does not yet exist. See API permissions.

Two things happen at POST /users/provision that are easy to miss:

  1. An account may be created. If nobody holds this provider identity and nobody holds this email address, the organization's account patterns decide whether an account is made. No match refuses the login.
  2. An existing account is brought into step with the provider. A rename, a new address, a new photo — all applied here, before the token is minted, so the token reflects what is true now rather than at the last login.

An account is identified by what the provider calls it (provider + providerUserId), not by email address. An address changes; the provider's identifier does not. Email is used for exactly one thing: recognising that someone signing in with a second provider is the same person, and attaching the new identity to the account they already have rather than making them a second one.

The machine flow

Script Identity API Account API
│ │ │
│─ POST /apikeyjwt ───────▶│ │
│ x-tagshape-api: ts_... │─ POST /apikeys/lookup ──▶│
│ │◀─ account + permissions ─│
│◀─ x-tagshape-auth: JWT ──│ │

The resulting token carries the same claims a person's would. Nothing downstream can tell an API key was involved.

Carrying the token

WhereUsed by
x-tagshape-auth headerService-to-service calls, and any machine caller
x-tagshape-auth cookieThe browser, calling its own site — this is how the management UI's token refresh arrives

Anything reading a request's identity looks in both. Looking in only one takes a signed-in caller for an anonymous one.

An API key is read from the header only. A key belongs to a machine with no session and no cookie jar, and honouring it from a cookie would let any site a signed-in user happens to visit spend their key for them.

See Headers for the complete list.