Skip to main content
WorkOS is authoritative for user roles and permission strings. Unkey uses WorkOS for authentication and role assignment, then translates the WorkOS permission strings from the access token into canonical Unkey resource permissions before the API constructs the principal. This translation exists because WorkOS permission strings cannot represent Unkey resource permissions directly. WorkOS permission slugs are capped at 48 characters and cannot contain /, so they cannot encode canonical Unkey resource paths. The WorkOS permission model is intentionally much smaller than Unkey’s resource permission model. The exact list of supported WorkOS permissions and their Unkey translations is defined in pkg/auth/workos/permissions.go. That Go file is the source of truth.

Permission shape

WorkOS recommends clear, concise permission slugs with a resource and action delimiter. Unkey follows that shape and keeps WorkOS permissions broad:
{area}:{action}
For example:
keys:create
The WorkOS slug is intentionally not a Unkey resource permission. It is stable input from the identity provider. The API translates it after token verification because only Unkey owns the resource-name contract.

Translation

The WorkOS resolver wraps the generic JWT JWKS resolver. The generic resolver verifies issuer, audience, signature, and time claims, and builds the initial JWT principal. The WorkOS wrapper then replaces the raw WorkOS permission strings with canonical permissions in this format:
unkey:v1:{workspace_id}:{resource_path}#{action}
A WorkOS permission string such as:
deployments:create
becomes a resource permission for the principal’s workspace:
unkey:v1:{workspace_id}:projects/**#create_deployment
The translated permission is the only value handlers see. Handler authorization does not depend on WorkOS permission names.

Unknown permissions

Unknown WorkOS permission strings are ignored during translation. They don’t grant access, and they don’t fall back to legacy wildcard permissions. This makes WorkOS safe to contain permissions that are not yet understood by the API. Adding a new permission requires updating the mapping table in pkg/auth/workos/permissions.go and adding tests for the resulting Unkey resource permission.

Ownership boundaries

The generic JWT package must stay provider-neutral. It verifies JWTs and returns claims as-is. WorkOS-specific behavior belongs in pkg/auth/workos:
  • the WorkOS issuer constant,
  • the WorkOS JWKS resolver wrapper,
  • the WorkOS permission mapping table, and
  • tests for WorkOS permission translation.
API configuration uses the WorkOS wrapper only for JWKS-backed WorkOS access tokens. HMAC JWT auth continues to use the generic JWT resolver directly.