Token Integration
Generating tokens for embedded dashboards with Unified Security
When a connection uses Unified Security, the token request shifts from carrying security policy details to identifying who the user is. Admins define the policies; the token tells Semaphor which actor to resolve them for.
This page covers how to structure token requests for connections in unified mode. For the full token API reference, see Token Options and Tokens API.
What Changes in Unified Mode
In legacy mode, your token request carries security policies (cls, rcls, sls) with concrete parameter values. In unified mode, those policies live on the server as policy definitions and assignments.
Your token request needs to provide:
- Actor identity -- who is this user? (
tenantId,endUserId,orgUserId) - Security params (optional) -- values for any unresolved
{{ placeholder }}in the policy definition templates, via thesecurityParamsfield
That's it. Semaphor resolves the effective security context from persisted assignments plus any securityParams you supply.
Prefer assignment-bound parameters when possible
For the simplest integration, bind parameter values directly in assignments. Your token request stays as simple as passing actor identity, and admins manage all security values in one place. Use securityParams when values genuinely vary per request — such as a user-selected filter or session-specific context.
Legacy fields are rejected on unified connections
If a connection is in unified mode, passing cls, rcls, or sls in the token request will fail with: "Unified Security runtime cutover does not support legacy token cls/rcls/sls overlays." Remove these fields from your request body for unified connections.
Actor Identification
The token request identifies the actor using the same fields as before. Semaphor derives the actor type from the fields you provide, checked in this order:
| Fields Provided | Actor Type | Description |
|---|---|---|
orgUserId | ORG_USER | Organization-level user |
tenantId + endUserId | TENANT_USER | End user within a specific tenant |
tenantId alone | TENANT | Tenant-level actor (no specific user) |
If none of these fields are present on a unified connection, the request fails with: "Unified Security requires an organization, tenant, or tenant user actor context."
These fields work on both dashboard tokens and project tokens. See Token Options for the complete field reference.
Integration Scenarios
Scenario 1: Fully Admin-Managed (Recommended)
The admin creates policy definitions and assignments with all parameter values bound. Your token request only needs actor identity.
This is the simplest integration — and the recommended approach for most use cases. The admin manages all security values centrally, and your code has zero security logic.
Scenario 2: Admin Policy Definitions + Runtime Security Params
When some values genuinely vary per request and can't be pre-configured in assignments, you can supply them at token time via the securityParams field. The admin creates the policy structure and binds stable values in assignments; your code fills in the dynamic ones.
For example, the admin binds tenant_id in the assignment. You supply region and department at runtime because they change per session.
Security params fill unresolved {{ placeholder }} values in the policy definition templates. They can narrow access but cannot widen beyond what persisted assignments allow.
Scenario 3: No Assignments (Unrestricted Access)
If a connection is in unified mode but the actor has no matching assignments, the request proceeds with the base connection -- no Unified Security restrictions are applied.
This is useful during incremental migration. You can switch a connection to unified mode and add assignments for actors over time. Actors without assignments continue using the connection as-is.
Audit before switching modes
Before switching a connection to unified, verify that all actors who need security restrictions have assignments. Use the Resolution Preview in the admin UI to check any actor's effective policy.
The securityParams Field
In unified mode, the securityParams field supplies values for unresolved {{ placeholder }} parameters in your policy definitions. If an admin left a placeholder unbound in the assignment, your token request fills it at runtime.
securityParams vs params
The securityParams field is for Unified Security placeholder values (CLS/SLS/RLS templates). The separate params field is for general runtime preferences like calendarContext, currencyFormat, and timezone. See Token Options for the full field reference.
Each key in securityParams matches a {{ placeholder }} name in the policy definition. If the placeholder uses @secret, see the next section for how secrets are handled.
Secret Parameters (@secret)
Policy definitions can mark sensitive placeholders with an @secret suffix -- for example, {{ password@secret }} in a CLS connection template. Secret values are passed in a separate secretSecurityParams field on the token request, not in securityParams. Semaphor encrypts them server-side so the plaintext never appears in the signed JWT.
How it works
- You send the plaintext secret in the
secretSecurityParamsfield, using the plain key name (without the@secretsuffix). - Non-secret values go in
securityParamsas usual. - Semaphor validates the secret against applicable CLS templates, stores it server-side, and replaces it with an opaque lookup reference.
- The signed JWT carries the reference, not the plaintext secret.
- At query time, Semaphor resolves the real secret server-side when rendering the CLS template.
The plaintext secret is never embedded in the token payload.
Example
Given this CLS policy definition:
Your token request separates plain values from secrets:
The resulting JWT payload contains a reference for the secret, not the plaintext:
Notice that both values end up under securityParams in the JWT -- but the password is an opaque reference, not the plaintext. At query time, Semaphor resolves 9c4d2c91-... back to the real password server-side and renders the connection string.
Key naming
Always use the plain key name -- write password, not password@secret. The @secret suffix only appears in the policy definition template to tell Semaphor how to handle the value. Plain values go in securityParams; secret values go in secretSecurityParams.
Do not mix secret and plain keys
A key cannot appear in both securityParams and secretSecurityParams. If a key matches an @secret placeholder in a CLS template, it must be in secretSecurityParams -- passing it in securityParams will return an error.
Dashboard Tokens vs Project Tokens
Both token types work with Unified Security. The difference is scope, not security behavior.
| Dashboard Token | Project Token | |
|---|---|---|
| Credentials | dashboardId + dashboardSecret | projectId + projectSecret |
| Actor identity | tenantId, endUserId | orgUserId, tenantId, endUserId |
| Security params | securityParams field | securityParams field |
| Secret security params | secretSecurityParams field | secretSecurityParams field |
| Security mode | Respects per-connection mode | Respects per-connection mode |
| Mixed modes | Works (per-connection) | Works (per-connection) |
When a project has some connections in legacy mode and others in unified mode, both are handled correctly within the same token. Each connection resolves security independently based on its own mode.
What NOT to Do
Do not mix legacy security fields with unified connections
The following token request will be rejected if the connection is in unified mode:
Remove cls, rcls, and sls from your request body. Use the securityParams field for runtime security values instead.
If you need legacy security fields for some connections, keep those connections in legacy mode. Per-connection mode switching lets you migrate incrementally.
Best Practices
- Bind stable values in assignments. If a value is fixed per actor — database name, tenant ID, schema — put it in the assignment. This keeps your token code simple and gives admins centralized control over security configuration.
- Use
securityParamsfor genuinely dynamic values. Values that change per request or per session (e.g., a user-selected region filter, a time-scoped access window) are a good fit forsecurityParams. There is no performance penalty for plain security params — they pass through to the token without additional processing. - Prefer assignment-bound secrets over token-time secrets. Secret parameters (
@secret) passed viasecretSecurityParamsrequire server-side encryption and storage on every token request. Binding secrets in assignments avoids this per-request overhead and keeps sensitive values out of your application code entirely.
Error Reference
Common errors when using Unified Security with tokens:
| Error Message | Cause | Solution |
|---|---|---|
| "Unified Security requires an organization, tenant, or tenant user actor context" | No actor identity fields in the token request | Pass orgUserId, tenantId, or tenantId + endUserId |
| "Unified Security runtime cutover does not support legacy token cls/rcls/sls overlays" | Legacy cls, rcls, or sls fields on a unified connection | Remove these fields; use securityParams for runtime security values |
| "placeholder 'X' is required but no value was provided" | A policy definition placeholder has no value from assignments or securityParams | Supply the missing value in the securityParams field |
| "secret placeholder 'X' could not be resolved" | A @secret parameter references an invalid or missing secret | Check the secret configuration in the admin UI |
| "Unified Security actor validation failed" | The actor (org user, tenant, or tenant user) does not exist or does not belong to the project | Verify the actor exists and is associated with the project |
Migration Checklist
When moving a connection from legacy to unified:
- Create policy definitions with the same policy logic you had in token-based CLS/RCLS/SLS.
- Create assignments for each actor, binding the parameter values that were previously in your token requests.
- Use the Resolution Preview to verify each actor's effective security matches your expectations.
- Remove
cls,rcls, andslsfields from your token generation code. Move any runtime security values tosecurityParams. - Switch the connection to
unifiedmode. - Test with each actor type to confirm correct behavior.
For a detailed migration walkthrough, see the Migration Guide.
Next Steps
- Security Overview -- how Unified Security works
- Policy Types -- CLS, SLS, and RLS configuration details
- Policy Definitions & Assignments -- create and manage policy definitions
- Token Options -- full token API field reference