Skip to main content

Delegation

EndpointMethodAuthDescription
{prefix}/subject/:id/actorsPOSTAdminAdd an authorized actor for delegation
{prefix}/subject/:id/actors/:actorIdDELETEAdminRemove an authorized actor
{prefix}/delegated-tokenPOSTAuthRequest token to act on behalf of another subject

Auth = Bearer token or refresh token cookie. Admin = Auth + isAdmin required.

Delegation allows one authenticated subject to act on behalf of another (e.g., admin impersonation for support). The principal's permissions apply; the actor's identity is recorded for audit. See JWT Claims: Delegation for the act claim format.

Non-human actors (coming soon)

Currently, the actor must be an authenticated subject and the principal must be a valid subject (exists in the database). Service account and AI agent authentication (API keys, service tokens) is planned for a future release.

Admin delegation: Admins can delegate as any subject — no setup needed. Authenticate, request a delegated token, done.

Non-admin delegation flow:

  1. Authorize actor — an admin adds the actor via Add Authorized Actor
  2. Actor authenticates normally — logs in via magic link or invite, gets their own access token
  3. Actor requests delegated token — calls Request Delegated Token with their access token and the principal's sub
  4. Auth verifies and issues token — checks that the actor is authorized for the principal. Token has sub = principal, act.sub = actor
  5. Actor makes calls — guards check sub (principal's permissions), logs show act.sub

Add Authorized Actor

POST {prefix}/subject/:id/actors — Admin required

Adds an actor to a subject's authorized delegation list. The actor must be a valid subject ID — returns 400 "Actor ID not found: {id}" if not. Idempotent — adding the same actor twice is a no-op.

const response = await fetch(`/auth/subject/${targetSub}/actors`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${adminAccessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ actorSub: actorSubId })
});
const { subject } = await response.json();
// subject.authorizedActors now includes actorSubId

Remove Authorized Actor

DELETE {prefix}/subject/:id/actors/:actorId — Admin required

Removes an actor from a subject's authorized delegation list. Idempotent — removing an actor that isn't authorized is a no-op.

const response = await fetch(`/auth/subject/${targetSub}/actors/${actorSubId}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${adminAccessToken}` }
});
const { subject } = await response.json();
// subject.authorizedActors no longer includes actorSubId

Request Delegated Token

POST {prefix}/delegated-token — Auth required

The actor uses their own access token and specifies who to act for:

const response = await fetch('/auth/delegated-token', {
method: 'POST',
headers: {
'Authorization': `Bearer ${actorAccessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
actFor: targetSub // Subject ID to act on behalf of
})
});
const { access_token } = await response.json();
// Token claims: { sub: targetSub, act: { sub: actorSub }, ... }

Fails if: the actor is not an admin and has not been authorized for the principal.

Using Delegated Tokens

Delegated tokens work like regular tokens. Your DO reads the JWT from the Authorization: Bearer header (see How the JWT Reaches Your DO) and checks sub for authorization. The act chain is available for audit logging.

Delegated token refresh

LumenizeClient auto-refreshes regular access tokens using the refresh token cookie. Delegated tokens require a separate refresh flow: the actor must first refresh their own access token, then call /auth/delegated-token again. LumenizeClient does not currently auto-refresh delegated tokens — your application is responsible for re-requesting them when they expire.

// Guard checks sub (principal's permissions)
if (claims.sub !== ownerId) throw new Error('Forbidden');

// Audit logging includes actor if present
const actor = claims.act ? `${claims.act.sub} for ` : '';
console.log(`Document updated by ${actor}${claims.sub}`);

For testing delegation flows, see Testing: Delegation in Tests.