Core Concepts
Understand the building blocks of Vaultaris — tenants, users, roles, groups, applications, sessions, and the security primitives that connect them.
Tenants
A tenant is the top-level isolation unit. Every resource in Vaultaris — users, roles, groups, applications, sessions, audit logs — belongs to exactly one tenant and is never visible to another.
Typical mapping:
- SaaS product → one tenant per paying customer organization
- Internal tooling → one tenant per business unit or environment
Tenants are identified by a UUID returned at creation. All resource routes are scoped under /api/v1/tenants/{tenant_id}/.
The master tenant (
00000000-0000-0000-0000-000000000001) is reserved for instance-level administration.
Hosted tenants
A tenant whose license includes the hosting capability (granted by the control plane) can act as a host for other tenants on the same instance. Each hosted tenant is fully isolated — the host gets administrative and aggregate-stats access only, never read access to the hosted tenant's data.
Billing shadow tenants
A special tenant variant (is_billing_shadow = true) used by the cloud control plane to hold billing RBAC. Billing shadow tenants have four seeded roles (billing.owner, billing.admin, billing.finance, billing.viewer) and are excluded from OpenAPI docs. They are provisioned automatically when a user signs up via the cloud portal.
Users
A user is a person or service account that can authenticate within a tenant. Users carry:
- Email address (unique within a tenant)
- Argon2id-hashed password
- Profile fields: first name, last name, display name, phone, locale, timezone, avatar URL
- Email verification status
- MFA enrollment (TOTP, WebAuthn / passkeys)
- Lockout state:
failed_attempts,locked_until - Freeze state:
freeze_reason(LicenseDowngrade, Expiry, Suspension, AdminAction)
Roles
A role is a named permission set scoped to a tenant or application. Roles can be:
- Simple — flat permission list
- Composite — inherit permissions from other roles (
is_composite = true) - System — built-in roles protected from modification (
is_system = true)
A user's effective permissions are the union of all permissions from direct roles and roles inherited through group membership.
Permissions
A permission is the atomic authorization unit in the resource:action model (e.g. users:read, tenants:write). Permissions support ABAC conditions for attribute-based gating. They are assigned to roles.
Groups
A group is a collection of users that share role assignments. Groups support:
- Hierarchical nesting via
parent_id(path-based) - Identity provider allowlists — restrict which IdPs members can use
- OAuth client allowlists
global_session_enabledflag for cross-domain SSO access
Applications
An application represents a logical service within a tenant. Applications can own scoped copies of OAuth clients, IdPs, roles, groups, permissions, and ABAC policies — keeping each service's authorization surface self-contained. Applications are subject to license gating (the applications feature must be enabled for the tier).
OAuth Clients
An OAuth client is the OAuth 2.0 credential set for a specific application or integration:
client_id(public)client_secret(hashed — confidential clients only)client_type:publicorconfidential- Allowed redirect URIs, grant types, scopes
- Token lifetime overrides
- PKCE requirement flag
- Consent requirement flag
DPoP (Sender-Constrained Tokens)
DPoP (RFC 9449) binds access and refresh tokens to the client's key pair. The client generates an ed25519 or P-256 key pair, proves possession on every request via a DPoP header JWT, and the server rejects any request that cannot prove ownership of the key the token was issued to.
This prevents token replay: a stolen bearer token is useless without the client's private key.
Sessions
Regular sessions
Short-lived, created on authentication. Stored in PostgreSQL, tied to tenant, user, IP, and user-agent. Instantly revocable.
Global sessions
Long-lived (up to 1 week), issued when a user is in a group with global_session_enabled = true. Enables cross-domain SSO without third-party cookies. Domain transfer tokens (one-time, 60-second lifetime) carry the session across domains.
Device Registry
Every login tracks a device derived from the User-Agent string. Devices can be:
- Trusted — marked explicitly by the user or admin
- Revoked — blocked from further sessions
- New device login — triggers email alert and plugin hook
Each device has a full session history. Device management is at /api/v1/tenants/{tenant_id}/users/{user_id}/devices.
Freeze / Unfreeze System
When a license downgrades or expires, Vaultaris freezes resources to bring the instance within the new limits:
- LIFO freeze — newest resources frozen first
- FIFO unfreeze — oldest resources restored first on upgrade
- Skips — system admin users are never frozen
- Admin freeze — manual freeze via admin action; never auto-unfrozen on upgrade
- Scope — Users, OAuthClients, Applications, IdPs, Groups
Frozen resources are listed at GET /api/v1/tenants/{tenant_id}/frozen.
ABAC Policies
Attribute-based access control policies layer on top of RBAC. Each policy has:
resource_type+actionpatterneffect: Allow or Deny (deny-wins)priorityorderingconditions: 20+ operators (equals, in, gt, lte, regex, in_cidr, between, …)status: Active, Inactive, or Testing
The ABAC engine evaluates after RBAC. A Deny policy short-circuits all further evaluation.
Audit Log
Every significant action produces an append-only, tamper-evident audit record with: actor, action enum, target resource, timestamp, IP, user-agent, and JSON change metadata.
Plugins
Plugins extend Vaultaris via native Rust dynamic libraries (.so / .dylib). They are compiled against the same ABI using stabby for stability guarantees.
12 plugin categories: auth_provider, identity_provider, storage_backend, notification_channel, encryption_provider, policy_engine, audit_sink, jwt_customizer, rate_limiter, metrics_collector, input_validator, lifecycle_hook.
Plugins are installed globally and activated per-tenant. Each tenant gets its own config chain and plugin instance — two tenants sharing a plugin never share state. See Plugins for the full SDK reference.
Token Types
| Token | Default lifetime | Purpose |
|---|---|---|
| Access token | 1 hour | Bearer credential for API calls |
| Refresh token | 24 hours | Exchange for new access token |
| ID token | 1 hour | OIDC identity assertion |
| Global session token | 168 hours (1 week) | Cross-domain SSO |
| Authorization code | 5 minutes | Intermediate code in auth code flow |
| MFA token | 10 minutes | Intermediate credential during MFA challenge |
| DPoP-bound token | same as bearer | Access/refresh token bound to client key pair |
Lifetimes are configurable per tenant and per application.