Overview

Orgs, clients, tenants, and how they compose.

LoginWith has four core primitives. They’re independent enough to reason about separately and overlap enough that you rarely think about them.

Org

An org is a billing + administrative boundary. Every resource belongs to exactly one org. It owns a slug (acme), a display name, branding, and billing. In token claims the org appears as the issuer (iss: https://acme.loginwith.app/) and the API audience (aud: https://acme.loginwith.dev).

Client

A client is an OAuth 2.0 client registered within an org. It’s the thing your app holds credentials for. Each client has:

  • A client_id (public) and optional client_secret (server-side only)
  • A list of registered redirect_urls
  • A client_type: public (SPA, no secret) or confidential (server, has secret)
  • A response_type: code (authorization code grant) or token (implicit)

Most apps end up with two clients: one public SPA client for the browser, one confidential client for their backend.

Tenant

A tenant is a namespace within an org. Think of it as the “team” or “workspace” scope your users belong to.

A minimal setup has one tenant per org — users sign in and they’re just “in the org.” A multi-tenant setup has many tenants, each with its own membership rules (email domain, invite-only, open enrollment). Tokens carry the active tenant as tnt: "tnt_...".

User

A user is the person signing in. One user can belong to many tenants across many orgs (the “console client” path supports this directly). The authoritative user id is sub: "uid_..." in the access token.

How they fit together

flowchart TD
  Org[Org: acme]
  SPA[Client: public SPA<br/>acme.com]
  Srv[Client: confidential server<br/>api.acme.com]
  Default[Tenant: default]
  EU[Tenant: acme-eu]
  U1((user))
  U2((user))

  Org --> SPA
  Org --> Srv
  Org --> Default
  Org --> EU
  Default --> U1
  EU --> U2

A user token is authoritative about all five at once: which org, via which client, for which tenant, as which user, at which issuer.