Membership mapping and lifecycle
Nanaade uses the integration credential to identify the tenant and the signed assertion to identify its authenticated user. In the default jit mode, Nanaade creates the user and tenant relationship on first launch. Tenants that require roster-only access can instead use pre_provisioned mode.
First-launch resolution
For an active tenant, Nanaade resolves identity in this order:
- Find a target-tenant membership whose
externalSubjectequalssub. - Otherwise find a target-tenant membership whose
normalizedEmailequals the lowercased assertion email. - Otherwise find the global Nanaade user by normalized email.
- If no user exists and JIT is enabled, create the user.
- If the user has no conflicting sponsored membership, create the active target membership.
If an email-matched membership has no external subject, Nanaade stores sub and updates lastAccessedAt.
Assertion: sub=student_10482, email=amara@northbridge.edu
Membership: externalSubject=null, normalizedEmail=amara@northbridge.edu
Result: membership is bound to student_10482
Later launches resolve by the subject. If the same membership is already bound to student_10482 but the assertion supplies student_90210, Nanaade returns 409 SSO_SUBJECT_MISMATCH.
Just-in-time user creation
Suppose Amara exists only in the university portal:
{
"sub": "student_10482",
"email": "amara@northbridge.edu",
"name": "Amara Okafor"
}
On the first valid launch Nanaade creates:
User
email: amara@northbridge.edu
role: student
authMethod: tenant_sso
emailTrust: tenant_asserted
TenantMembership
tenant: Northbridge University
role: member
status: active
externalSubject: student_10482
No Nanaade password or email verification step is required. The tenant has already authenticated the person and attests to the identity by signing the assertion. Nanaade still controls tenant type, Nanaade role, permissions, modules, and data isolation.
Choose a stable subject
Use your immutable internal user ID:
const identity = {
sub: databaseUser.id, // e.g. "usr_01J4M8..."
email: databaseUser.email,
};
Do not use email, employee/student number if it can be reassigned, a login session ID, an OAuth access token, or a random UUID generated during launch.
Membership states
| State | SSO access | Operational meaning |
|---|---|---|
| Invited | Denied | A roster invitation or pending transfer exists but is not active. |
| Active | Allowed | Role, permissions, and tenant entitlements are evaluated. |
| Revoked | Denied immediately | Sponsored access was withdrawn. |
| Ended/transferred | Denied | Historical membership remains for audit purposes. |
Removing a module is different from revoking membership. Module removal blocks that capability; membership revocation blocks all tenant-sponsored access.
Example JIT onboarding flow
- Amara signs in to the university portal.
- The portal backend loads Amara's immutable ID, email, and name from trusted server state.
- The backend signs a fresh, one-time assertion.
- Nanaade creates the identity and active membership atomically.
- The browser enters the branded tenant workspace with only licensed modules.
Transfers and duplicate access
V1 permits one active sponsored member tenant per Nanaade user. If the signed email belongs to someone active under another sponsored tenant, Nanaade redirects to a generic conflict page and creates no second active membership.
The user can:
- request a membership transfer;
- contact Nanaade support; or
- return safely to the tenant portal.
A transfer request creates an invited destination membership and a pending, auditable request. Access stays with the original tenant until an administrator approves the transfer. Nanaade intentionally does not disclose the original tenant's name to the requesting tenant.
Troubleshooting mapping
SSO_MEMBERSHIP_REQUIRED: the tenant uses roster-only provisioning and no membership exists.SSO_MEMBERSHIP_INACTIVE: the matching invited, suspended, or revoked membership cannot launch.SSO_TENANT_TRANSFER_REQUIRED: the identity has active sponsored access under another tenant; use the browser conflict flow.SSO_SUBJECT_MISMATCH: verify your immutable ID mapping; do not rotate subjects.- User enters but sees fewer features: membership succeeded; inspect role, permissions, and tenant modules.
- User changed email: keep the original subject and update membership/user email through the approved account workflow.