Understanding the Cirata Symphony Security Model
Cirata Symphony implements a layered security architecture that combines OpenID Connect (OIDC) authentication, multi-tenant isolation through NATS accounts, and capability-based authorization via API keys. This page explains the concepts behind each layer and how they work together.
Security Layers
The security model is built on three foundational layers:
- Authentication—Verifying user identity via OIDC
- Tenant Isolation—Isolating users through NATS accounts with cryptographic JWT tokens
- Authorization—Controlling access through capabilities (API keys) and optional RBAC roles
Authentication
OpenID Connect (OIDC)
Symphony authenticates users through an external OpenID Connect (OIDC) identity provider. Any standards-compliant OIDC provider can be used. There are two approaches:
-
Bundled Keycloak—some deployment methods include an optional bundled Keycloak instance that is pre-configured and ready to use with no external setup. Keycloak can also federate to upstream identity providers (Google Workspace, Azure AD, etc.) via its identity brokering feature.
-
External OIDC provider—point Symphony directly at any OIDC-compliant provider such as Okta, Auth0, Microsoft Entra ID, Google Workspace, or an existing Keycloak deployment. See OIDC Configuration for setup details.
When a user attempts to access Symphony:
- The browser is redirected to the configured OIDC provider
- The user authenticates with their credentials
- The OIDC provider issues an ID token and access token
- Symphony validates the tokens and extracts the user's subject identifier (email or username)
- A session is established in the browser
Session Idle Timeout
Symphony monitors user activity in the browser and enforces an idle timeout. When a user is inactive for the configured duration (default: 30 minutes), Symphony stops renewing access tokens with the OIDC provider, allowing the session to expire naturally. When the user returns:
- If the OIDC session is still valid, the session resumes seamlessly.
- If the OIDC session has expired, the user is redirected to the login page with a notification that their session has expired.
Administrators can configure the idle timeout duration in Admin → Settings. The timeout can be set from 5 minutes to 8 hours.
The OIDC provider remains the authoritative source of session validity—Symphony does not maintain its own server-side session state. Instead, it cooperates with the provider by pausing token renewal during idle periods.
API Token Authentication
For programmatic access, API keys provide bearer token authentication. Each API key includes:
- A unique token for HTTP Bearer authentication
- A NATS JWT credential for direct messaging access
- Specific capabilities that define allowed operations
Tenant Isolation
NATS Account Model
Cirata Symphony creates a separate NATS account for each user. Each account is cryptographically isolated:
- Account JWT—Signed by the Symphony operator, defines the account's identity and imports
- Account Key Pair—Public key identifies the account; private signing key signs user JWTs
- Subject-based Permissions—Controls which NATS subjects the account can publish to or subscribe from
User accounts import specific subjects from the Symphony account, enabling controlled access to:
- Shared user directory (
symphony_users) - Extension sharing catalog (
symphony_shares) - RBAC role definitions (
symphony_roles) - Role assignments (
symphony_role_assignments)
Accounts cannot directly access other users' data. Resources are shared explicitly through the extension sharing mechanism, which requires both parties to opt in.
User JWT Credentials
When a user creates an API key, Symphony generates a user JWT that includes:
- Identity—Links to the parent NATS account
- Permissions—Publish and subscribe subject patterns
- Expiration—Optional time-to-live
- Signature—Signed by the account's signing key
This JWT is provided to the client and used for all NATS operations. The JWT's permissions define exactly which subjects the credential can access.
Authorization
Capability-Based Model (API Keys)
API keys are the primary authorization mechanism in Symphony. Each key defines specific capabilities using NATS subject patterns:
- Publish permissions (
pub.allow) control which NATS subjects the key can send messages to - Subscribe permissions (
sub.allow) control which subjects the key can receive messages from
Users can create multiple API keys with different capabilities for different purposes:
- Full access key—
cirata.>for administrative operations - Extension-specific key—
cirata.extensions.myext.>for a single extension - Read-only key—Subscribe permissions only, no publish rights
- Service-specific key—Access to specific Symphony services
Every API key, regardless of how it was created, is barred at the NATS protocol level from reading or writing protected platform buckets (user records, API keys, RBAC roles, licensing, and similar system data). This applies even to keys held by administrators—platform integrity is not delegable to a credential.
Role-Based Access Control (RBAC)
RBAC is an optional layer that provides centralized permission management, particularly useful in enterprise environments with LDAP or Active Directory. When enabled, RBAC maps OIDC group claims to Symphony roles, and roles define the ceiling on what API keys a user can create.
For configuration details, see Role-Based Access Control.
How the Layers Work Together
Each level in the security hierarchy constrains the next:
- Operator JWT—Root trust, signs account JWTs
- Account JWT—Defines account identity, imports, and JetStream limits; signed by operator
- User JWT—Defines credential permissions; signed by account signing key
- API Key—User JWT with specific subject permissions
A user JWT cannot grant more permissions than the account JWT allows. When RBAC is enabled, API key creation is further constrained—users cannot create keys with capabilities that exceed their role permissions.
Security Without RBAC
If RBAC is not configured, Symphony operates with capability-based security only:
- All authenticated users receive full NATS permissions (
cirata.>) - Users can create API keys with any capabilities
- Access control is delegated to the user via their API key design
This mode is suitable for small teams, development environments, or deployments without LDAP/AD infrastructure.
Best Practices
For Administrators
- Enable RBAC in Production—Use role assignments for centralized control in multi-user environments
- Configure Admin Designation—Set
admin_grouporadmin_subjectto exit bootstrap mode - Use Least Privilege Roles—Design roles with minimal necessary permissions
- Audit Role Assignments—Regularly review which groups map to which roles
- Set an Appropriate Idle Timeout—Configure the idle timeout in Admin → Settings to balance security and user convenience
For Users
- Create Specific API Keys—Avoid creating keys with broad
cirata.>permissions unless necessary - Use Extension-Specific Keys—Create separate keys for each extension or service
- Set Key Expiration—Use short-lived keys when possible
- Store Tokens Securely—Treat API key tokens as sensitive credentials
For Extension Developers
- Request Minimal Permissions—Document the minimum subjects required for your extension
- Use Subject Namespaces—Prefix all your subjects with
cirata.extensions.<your-ext>. - Handle Permission Errors—Gracefully handle NATS permission denied errors
- Use Extension-Specific Storage—Extensions are automatically prevented from accessing sensitive platform buckets (user records, API keys, RBAC roles). Use the SDK's
addBucket()method to create extension-owned buckets for your data
See Also
- Role-Based Access Control—How to configure role-based access control
- Security Reference—Subject patterns, role definitions, and technical reference
- Access Control—All access methods and authentication flows