Organizations — B2B Login
Org selection on login · invitation-based signup · org_id claim and org-scoped roles
Login /authorize
organization=org_id on the authorization request
ID Token
org_id claim (+ org_name if enabled tenant-wide)
Session
every request in this session is scoped to that org
Three login-flow modes, one app can only run one
organization_require_behavioris configured per Auth0 application, not tenant-wide — but it's still static per app, not something that flips per request. This demo's app runs no_prompt (the app always decides). The other two modes: post_login_prompt (user logs in first, then picks an org via Auth0's org selector) and pre_login_prompt (user picks or is routed to an org before Universal Login even starts, via Organization Discovery by email domain or name).
This demo's tenant has one Organization pre-provisioned with an existing member and an org-scoped admin role already assigned. Sign in as that member, or use the invitation link below to see the other half of the flow — a brand new user joining the same org via redemption.
Log in to the organization →The invitation used here was created once via the Management API during setup — this demo doesn't mint invitations on demand, to avoid needing a Management-API-calling credential just to show what redemption looks like. Following the link takes you through /authorize?invitation=...&organization=..., where Auth0 signs the invitee up, verifies their email, and joins them to the org with the role the invitation specified — all in one step, before this app sees any of it.
Ask whoever set up this demo for a live invitation link — it's tenant-specific and expires, so it isn't hardcoded into this page.
Org selection happens at login, not after — the organization parameter travels on the authorize request itself. This app is configured organization_require_behavior: no_prompt, so it decides when to pass it, rather than Auth0 prompting the user to pick.
Invitations are a complete onboarding step, not just an email — redeeming one signs up the invitee, verifies their email, and applies roles in a single Auth0-hosted flow, with no follow-up API call from this app required.
Roles are scoped to the org, not the user globally — a role assigned via organizations/{id}/members/{user}/roles only applies while the session is authenticated through that specific org. The roles shown above come from event.authorization.rolesin a dedicated post-login Action, gated to this demo's own client_id so it has no effect on any other demo's login.
Strengths
- Membership and org-scoped roles live at the platform layer (Auth0's own organization/member/role model), not bolted on via app-level custom claims or a separate authorization store the app has to keep in sync itself.
- Invitation-based signup marks the invitee's email verified and applies the intended roles atomically on redemption — there is no window where an invited user exists without the access the inviter intended, or needs a second manual step.
Risks & Considerations
- organization_require_behavior is configured per Auth0 application, not tenant-wide, and is static per app — it is easy to assume a single client can flip between the three login-flow modes per request when it cannot; the app has to be provisioned for the mode it needs.
- An org-scoped role only applies while a session is authenticated through that org — a stale assumption that a role check is global (rather than checked against the currently active org_id) can silently under- or over-authorize a user who is a member of more than one org.
- Invitation links carry a ticket that grants real signup + role assignment on redemption — treat them with the same handling care as a password-reset link, not as a low-sensitivity URL.
Hardening Checklist
- Validate org_id, not org_name, when checking token claims — Auth0's own guidance is explicit that org_id is the preferred identifier for authorization decisions, with org_name treated as a secondary, use-case-specific option.
- Re-derive the active org from the validated session/token on every request that makes an authorization decision, rather than caching "which org is the user in" client-side across a session that could switch orgs.
- Set a short, deliberate ttl_sec on invitations (this demo uses 7 days) and treat unredeemed invitations as an attack surface worth expiring, not a fire-and-forget artifact.