Product Concepts
Curupira models identity and access control as a small hierarchy. Understanding it up front makes every integration decision obvious. The core chain is:
tenant ─┬─► application ─┬─► role ──────────────┐
│ └─► role group ─(has)─► roles
└─► user ─(assigned)─► roles and/or role groups
- A tenant owns everything.
- Applications and users belong to a tenant.
- Roles and role groups belong to an application.
- Users are granted roles and role groups; those become the
roles/permissionsclaims in their token.
Tenant
A tenant is an isolated organization boundary — think "one customer" or "one company". Everything else is scoped inside a tenant, and Curupira enforces isolation so one tenant can never read or affect another tenant's data.
- Identified by a unique slug (e.g.
acme) and a display name. - Owns its applications and its users.
- A tenant is always created with at least one application (you cannot have a tenant with no way to log in).
Application
An application is an OAuth2 client — a single piece of software that authenticates users through Curupira (a web app, a mobile app, an SPA, a backend service).
- Has a
client_id(a UUID) used in the authorization request. Safe to ship in client code. - Has an API key (secret). Confidential clients present it on the token endpoint via the
X-API-Keyheader; public clients (SPAs, mobile) instead rely on PKCE and do not need the key. See Authentication. - Has a set of registered redirect URIs. Curupira only redirects back to an exact-match registered URI — this is a core security control.
- Owns its roles and role groups.
- Can be enabled/disabled; a disabled application cannot issue tokens.
- The API key can be regenerated from the dashboard (invalidates the old key).
User
A user is an end-user identity that belongs to a tenant and can log in to that tenant's applications.
- Identified by email (unique per tenant) with a hashed password, or provisioned via SSO (Google / Microsoft / GitHub) if enabled for the tenant.
- Carries flags such as
email_verifiedanddisabled. - Gains permissions by being assigned roles and/or role groups. In the admin dashboard, user management is view + assign — you list users and manage their role/group assignments (self-service user CRUD is handled by the sign-up flow, not the dashboard).
Role
A role is a named permission bucket that belongs to a single application (e.g. admin,
editor, viewer).
- Belongs to one application (
application_id). - Has a
nameand optionaldescription. - When a user holds a role, that role's name appears in the token's
rolesclaim, and its associated permission strings are aggregated into thepermissionsclaim.
Role group
A role group bundles several roles together so you can assign them as one unit (e.g. a
support-team group that contains viewer + ticket-responder).
- Belongs to one application.
- Contains member roles (
role_group_members). - Assigning a role group to a user is equivalent to granting every role inside it — useful for keeping permission sets consistent across many users.
How permissions reach your app
When a user completes login, Curupira issues:
- an
id_token(OIDC, RS256 JWT) — proves identity, contains standard claims plustenant,roles, and aggregatedpermissions; - an
access_token— sent to your APIs / to/oauth2/userinfo; - a
refresh_token— used to obtain new tokens without re-prompting the user (rotated on every use).
Your application reads the roles / permissions claims (after verifying the token
signature against the JWKS) to make
authorization decisions. See Authentication for the token contents and
verification steps.
The admin/RBAC layer (operators)
Beyond the per-tenant model above, Curupira has a separate admin RBAC layer used to operate the platform itself:
- admin roles (e.g.
super_admin) grant permissions over the admin API, scoped to a tenant via admin user-roles. - A break-glass super admin (environment-driven, cross-tenant, fully audit-logged) exists
for DW-Corp support. Its access to tenant data is logged as
super_admin_accessevents that tenant admins can see. This is an operator feature, not something subscribers configure.
Every administrative change is written to audit logs (who changed what, old vs. new values), and security-relevant activity is captured in login attempts and event logs.