There are two kinds of user. Org users (you and your team) sign in to API Studio to build. App users are the end-users of your deployed app. This page is about app users — the people who call your live endpoints.

Accounts are created on first sign-in

App users don't have a separate registration step. The first time someone signs in — by email/password or OAuth — their account and workspace membership are provisioned inline.

Token exchange

Your app obtains an identity token from the provider, then exchanges it for a nostackai app JWT at the token endpoint. The app JWT is what every data API call carries.

http
GET /app/{orgCode}/token
  oauthtoken: <provider id token | password-login token>
  x-client-id: <your app client id>

-> 200, header  x-nostackai-token: <app JWT>

The token Lambda validates your client_id against the org record, checks the token issuer against the allowlist, resolves the user's workspace, and signs the app JWT (valid ~48h).

OAuth providers

  • Google — the browser gets a Google ID token via the Sign-In SDK and posts it to the token endpoint. No discovery needed.
  • Okta / Auth0 (and any OIDC) — a PKCE redirect flow. The frontend discovers the org's provider by email domain, redirects to the IdP, exchanges the code for an ID token, then calls the token endpoint. New OIDC providers work without code changes.

PKCE in one line

There's no safe place for a client secret in a browser, so PKCE replaces it with a one-time math proof: the client hashes a random verifier into a challenge up front, then proves possession of the verifier when exchanging the code.

What the app JWT carries

  • `org` — your org code (the claim is org, not org_code).
  • `tenant_id` / `tenant_code` — the active workspace, when resolved.
  • `role` — an app-defined label (e.g. admin). It is not enforced by the gateway — see ACL, roles & groups.
  • `email`, `fn`, `ln`, `picture`, `email_verified`, `clientid`, `iss` — identity and source.

The role claim grants nothing

The app authorizer ignores the JWT role. Permissions come only from ACL policies. The role is surfaced for your own in-app logic.