Skip to content

Roles and Permissions

Roles and permissions structure

In our application using SuperTokens, we maintain a clear separation between roles and permissions:

Roles

  • Definition: Roles represent user types or job functions (e.g., admin, coder, reviewer, validator)
  • Assignment: Roles are assigned per [user, tenantId] pair - a single user can have different roles in different tenants
  • Multi-tenancy: A user can belong to multiple tenants, with one role per tenant
  • Purpose: Group users by their function or responsibility level within a specific tenant
  • Naming: Use nouns describing the user's role (e.g., tim, internal-dim)

Permissions

  • Definition: Permissions are commands or actions that users can perform
  • Assignment: Permissions are assigned to roles (not directly to users)
  • Purpose: Define granular capabilities and operations
  • Naming: Use action verbs describing what can be done (e.g., c.ms.vc for validate-coding, c.ms.tac for trigger-ai-coding)

Disjoint Sets Principle

Roles ∩ Permissions = ∅

Roles and permissions must be completely separate - no name should exist in both sets. This prevents ambiguity and ensures clarity:

  • Bad: Having both a role validator and a permission validate
  • Good: Role validator with permission c.ms.vms (validate-medical-stay)

This separation ensures:

  • Clear distinction between "who someone is" (role) vs "what they can do" (permission)
  • Unambiguous authorization checks in code
  • Easier permission management and auditing

Implementation Flow

[User, TenantId] → assigned to → Role → contains → Permission(s) → checked in code

Example:

A user john.doe@example.com belongs to multiple tenants with different roles:

Tenant A (Hospital A):

  • User: john.doe@example.com
  • TenantId: tenant-hospital-a
  • Role: internal-dim
  • Permissions: c.vp, c.ms.tac, c.ms.vc, c.ms.rc

Tenant B (Hospital B):

  • User: john.doe@example.com
  • TenantId: tenant-hospital-b
  • Role: admin
  • Permissions: c.vp, c.ms.tac, c.ms.vc, c.ms.rc, c.ms.vms, st.vp, ...

The same user has different capabilities depending on which tenant context they're operating in.

Permissions Naming Convention

Problem: JWT Token Size Limits

When using SuperTokens with role-based permissions, all permissions assigned to a user's roles are stored in the JWT access token payload. JWT tokens have practical size limits (typically 4-8KB) imposed by:

  • HTTP header size limits
  • Cookie size limits
  • Browser and server configurations

When the total character count of all permissions exceeds ~1000 characters, the JWT token becomes too large, causing the SuperTokens provider to crash or fail silently.

Example: 21 verbose permissions like coding.medical-stay.view-flag-only-parallel total ~996 characters, approaching this limit.

Solution: Abbreviated Permission Names

To overcome JWT size limits while maintaining granular permissions, we use abbreviated permission codes.

Naming Convention

Format: <domain>.<subdomain>.<action>

Each segment is abbreviated using initials or short identifiers:

  • Domain: First letter(s) of the main service/module
  • Subdomain: First letter(s) of each word in the resource
  • Action: First letter(s) of each word in the action

Examples

Full PermissionAbbreviatedBreakdown
coding.view-pagec.vpcoding.view-page
coding.medical-stay.view-flag-only-parallelc.ms.vfopcoding.medical-stay.view-flag-only-parallel
coding.medical-stay.trigger-ai-codingc.ms.taccoding.medical-stay.trigger-ai-coding
coding.medical-stay.can-cancel-action.from-validatedc.ms.cca.fvcoding.medical-stay.can-cancel-action.from-validated
screenflow.view-pages.vpscreenflow.view-page
settings.view-pagest.vpstettings.view-page

Maintenance

Keep a reference table mapping abbreviated codes to their full descriptive names for clarity.