Skip to main content

Permissions

Permissions are the atomic units of authorization. Each permission is a branded nominal token -- a value that carries its identity at both the type level and runtime.

Why Branded Nominals?

TypeScript's structural type system means two objects with the same shape are interchangeable. For authorization, this is dangerous: you don't want ReadUsers to accidentally satisfy a check for WriteUsers just because they're both strings.

Branded nominal tokens solve this by giving each permission a unique phantom type brand. Two permissions with different names are different types, caught at compile time.

Cross-Boundary Identity with Symbol.for()

Permissions use Symbol.for() under the hood, which means:

  • Two createPermission("ReadUsers") calls in different modules produce the same runtime value
  • Identity comparison (===) works across module boundaries, bundle splits, and even separate packages
  • No global registry, no side effects -- Symbol.for() is the registry

Creating Permissions

import { createPermission } from "@hex-di/guard";

const ReadUsers = createPermission("ReadUsers");
const WriteUsers = createPermission("WriteUsers");
const DeleteUsers = createPermission("DeleteUsers");

Each call returns a branded permission token. The string name is used for:

  • Symbol.for() identity
  • Serialization (policies reference permissions by name)
  • Debugging and error messages

Permission Groups

When you have a set of related permissions, bundle them into a named group:

import { createPermissionGroup } from "@hex-di/guard";

const UserPermissions = createPermissionGroup("UserPermissions", {
read: ReadUsers,
write: WriteUsers,
delete: DeleteUsers,
});

// Access individual permissions
UserPermissions.read; // === ReadUsers
UserPermissions.write; // === WriteUsers
UserPermissions.delete; // === DeleteUsers

Groups are convenience wrappers -- they don't change how permissions work. Every permission in the group retains its individual identity. Groups are useful for:

  • Organizing permissions by domain (UserPermissions, OrderPermissions)
  • Passing related permissions as a bundle to role definitions
  • IDE autocompletion when working with large permission sets