Skip to main content
Unkey Resource Names, or URNs, identify public Unkey resources in a stable, parseable format. URNs are used anywhere Unkey needs to refer to the same resource across product surfaces, audit logs, permission checks, traces, and internal events. This document defines the v1 resource-name contract. Future versions can add path shapes or change parsing rules, but v1 URNs must keep the behavior defined here. A permission attaches an action to a URN, but the URN itself names only the resource. The Go implementation lives in pkg/urn.

Format

A URN has four colon-separated fields.
Each field has a fixed meaning. For example:
The workspace ID is part of the URN even when the caller already has workspace context. Audit logs, background jobs, and support tools must be able to copy a URN and identify the owning workspace without extra state.

Path rules

Resource paths are part of the contract. Code that creates, parses, or matches URNs must follow these rules.
  • Concrete resource URNs must use the full canonical path from the catalog.
  • Collection segments are plural, for example keyspaces, keys, and projects.
  • ID segments use the existing public Unkey ID for that resource.
  • : is reserved for top-level URN fields and must not appear in a resource path.
  • # is reserved for permissions and must not appear in a URN.
  • A resource path must not start or end with /.
Concrete URNs identify one resource. Resource-name patterns identify a set of resources and are part of the v1 URN grammar. Callers that need one exact resource, such as audit logs and authorization requests, must use concrete URNs. Stored authorization grants can use patterns.

Resource-name patterns

Resource-name patterns use the same four-field URN format as concrete resource names. The difference is in the resource path. The * operator must be the whole path segment. A pattern such as key_* is invalid because it would make prefix matching ambiguous. The /** operator must be the final path segment. A pattern such as projects/**/deployments/* is invalid because descendant matching has to stop at the end of the path. After a path uses * for an ID selector, descendant ID selectors must also use *. The path can still name child collections, but it can’t narrow back to a specific child. This keeps wildcard paths canonical and avoids permissions that pretend to select a child without selecting the parent that owns it. Valid:
Invalid:
For example, this pattern:
matches this concrete URN:
This descendant pattern:
matches the project itself and every public descendant below that project. Patterns never cross workspace boundaries, including the global workspace pattern:
pkg/urn parses concrete names and patterns. It also decides whether one URN covers another. The permission system adds the action suffix and decides what a covered resource authorizes. It doesn’t define its own path matching.

Resource catalog

The public catalog defines every concrete resource path that can appear in a v1 URN. Implementation code must reject concrete URNs that don’t match one of these path shapes. Pattern grants must still be built from these path shapes, with * replacing complete ID segments or trailing /** covering descendants.

Team

Team resources are rooted under team. Examples:

Billing

Billing resources are rooted under billing. Workspace quota is a singleton resource because quota applies to the workspace billing state. Examples:

Keyspaces

Key resources are rooted under the keyspace that owns the key. Examples:

Identities

Identity resources are rooted under identities. Example:

Rate limits

Standalone rate limiting resources are rooted under ratelimits. Overrides belong to the namespace they modify. Examples:

RBAC

RBAC resources are rooted under rbac. Relationship changes, such as adding a role to a key, are audited against both affected resources rather than by creating a separate join-table URN. Examples:

Deploy

Deploy resources use the full product hierarchy. A deployment belongs to one environment, which belongs to one app, which belongs to one project. Examples:

Portal

Portal resources are rooted under portals. Session tokens and sessions belong to the portal that created them. Examples:

Internal resources

Runtime and implementation resources are not part of the public v1 catalog unless a product feature explicitly promotes them. This includes:
  • Frontline routes
  • Regional counters
  • ClickHouse outbox rows
  • Cache entries
  • Join-table rows
Internal systems can still log implementation IDs in metadata. They must not mint public URNs for these resources unless the catalog is updated first.

Invalid examples

These strings are invalid URNs or invalid concrete URNs.