Migration Guide
Migrating from legacy security to Unified Security
This guide walks you through moving a connection from legacy token-based security (CLS, RCLS, SLS) to Unified Security. The migration is per-connection, reversible, and can be staged while your dashboards continue running.
Before You Start
A few things to know before migrating:
- Migration is per-connection. Different connections in the same project can use different security modes. You do not need to migrate everything at once.
- Legacy and unified coexist. A project can have some connections on
legacyand others onunifiedwith no conflicts. - You can stage your work. Create policy definitions and assignments while a connection is still in
legacymode. They have no runtime effect until you switch. - Switching is instant. Changing a connection from
legacytounified(or back) takes effect immediately. - No data is lost. Switching back to
legacypreserves all your unified policy definitions and assignments. They remain ready if you switch again.
Terminology Mapping
Unified Security renames and reorganizes several legacy concepts. Use this table as a reference.
| Legacy Term | Unified Term | What Changed |
|---|---|---|
| CLS (Connection Level Security) | CLS | Same concept. Policies are now defined in policy definitions, not token fields. |
| RCLS (Row/Column Level Security) | RLS (Row Level Security) | Renamed. Column-hiding is handled separately through CLS or database grants. |
| SLS (Schema Level Security) | SLS | Same concept, now defined in policy definitions with schema, schemaTemplate, or allowedSchemas. |
| TLS (Table Level Security) | (Deprecated) | No unified equivalent. Use SLS combined with database-level grants instead. |
Token cls field | Policy Definition + Assignment CLS config | Policies are admin-configured, not passed per token request. |
Token rcls field | Policy Definition + Assignment RLS config | Rules defined centrally with {{ placeholder }} params. |
Token sls field | Policy Definition + Assignment SLS config | Schema routing defined in policy definitions with optional parameterization. |
TLS removal
If you rely on Table Level Security (TLS), replace it with a combination of SLS boundaries and database-level grants before migrating. Unified Security does not include a TLS policy type.
Step-by-Step Migration
Step 1: Audit existing policies
Before creating anything in Unified Security, inventory what you have today.
For each connection, note:
- Which legacy policy types are in use (CLS, RCLS, SLS, TLS)
- The policy names referenced in your token generation code
- The parameter values passed per tenant or user
- Whether policies vary by tenant, by user, or are shared across all tenants
This inventory becomes your blueprint for policy definitions and assignments.
Step 2: Create policy definitions
For each connection, create one or more policy definitions that mirror your existing policies.
CLS -- Convert your connection policy name and its parameterized connection string (or file paths) into a connectionTemplate or filePathTemplates config with {{ placeholder }} syntax.
RLS (formerly RCLS) -- Convert each row-level policy into an RLS rule with a matcher and expression. Choose the matcher type that fits:
ALL_TABLES_WITH_COLUMNfor predicates that apply wherever a column existsTABLE_LISTfor predicates that apply to specific tablesSCHEMAfor predicates scoped to all tables in a schema
SLS -- Convert your schema parameter into an SLS config with schema, schemaTemplate, or allowedSchemas.
You can combine all three policy types in a single policy definition, or create separate policy definitions per policy type -- whichever matches your organizational needs.
Policy definitions are safe to create
Creating policy definitions on a legacy-mode connection has no runtime effect. Take your time getting the configuration right.
Step 3: Create assignments
For each actor (tenant, tenant user, or organization user), create assignments that bind a policy definition to that actor with concrete parameter values.
- Use
ALL_TENANTSscope for shared baseline rules (e.g., a common RLS predicate that all tenants inherit). - Use
TENANTscope for tenant-specific values (e.g., database name, schema, tenant identifier). - Use
TENANT_USERscope to narrow access for specific users within a tenant. - Use
ORG_USERscope for internal users who need scoped access.
Step 4: Preview and validate
Use the Resolution Preview in the admin UI to simulate security for different actors before going live.
- Navigate to Project Settings > Security.
- Select the connection and an actor.
- Review the resolved CLS, SLS, and RLS context.
Compare the resolved policies against your current token-based behavior. Verify that:
- All required parameters resolve without errors
- The effective CLS connection string or file paths match what your legacy token produces
- RLS predicates match the WHERE clauses your RCLS policies generate
- SLS routes to the correct schema
Step 5: Switch the connection to unified mode
In the connection settings, change Security Mode from legacy to unified.
The change takes effect immediately for all queries on that connection. Legacy token fields (cls, rcls, sls) will be rejected for this connection from this point forward.
Legacy token fields are rejected
Once a connection is in unified mode, token requests that include cls, rcls, or sls fields targeting that connection will return an error. Update your token generation code before or immediately after switching.
Step 6: Update token generation code
Remove the legacy cls, rcls, and sls fields from your token requests. Ensure actor identity fields are present so Unified Security can resolve the correct assignments.
Required actor fields:
| Actor Type | Required Fields |
|---|---|
| Tenant | tenantId |
| Tenant user | tenantId + endUserId |
| Organization user | orgUserId |
If some parameter values are not admin-bound in assignments and need to be supplied at runtime, pass them in the securityParams field.
Before and After
Here is a common use case -- a tenant with connection-level and row-level security -- showing the token request before and after migration.
Legacy token request
Unified token request
The CLS connection template and tenant-specific database name are now configured in a policy definition and bound to Acme via an assignment. The state filter is passed as a security param because it varies per request.
If state values are also admin-bound in the assignment, you can remove the securityParams field entirely -- the token request only needs actor identity.
Rollback
If something goes wrong after switching to unified mode:
- Open the connection settings.
- Change Security Mode back to
legacy. - The change takes effect immediately.
Your unified policy definitions and assignments are preserved -- they are not deleted when you switch back. Legacy token fields (cls, rcls, sls) will work again for this connection.
Use a feature flag during migration
Keep your legacy token generation code behind a feature flag while migrating. This lets you switch between legacy and unified token payloads without a code deploy.
Migration Checklist
Use this checklist to track your progress for each connection:
- Inventory existing CLS, RCLS, SLS, and TLS policies
- Replace any TLS usage with SLS or database grants
- Create unified policy definitions matching your legacy policies
- Create assignments for all actors that need security enforcement
- Preview resolved security for representative actors
- Compare resolved policies against legacy behavior
- Switch connection to
unifiedmode - Update token generation code to remove legacy fields
- Verify dashboards render correctly with unified security
- Remove legacy token code (or keep behind a feature flag)
Next Steps
- Security Overview -- understand the Unified Security model
- Policy Types -- CLS, SLS, and RLS configuration details
- Policy Definitions & Assignments -- create and manage policy definitions
- Multi-Tenancy (Legacy) -- reference for the legacy security model