Identity and tokens

Every read, write, count, page, stream, export, purge, and read marker is bound to workspace + environment (test or live) + app id + tenantKey + resourceType + resourceId. The host user id is the actor. A page URL or a bare resource id never authorizes a request.

Your server derives the user from its own session, checks that this user may open this resource, and mints the token with the secret key. The browser does not grant authority. A publishable key and allowedOrigins identify the workspace and apply CORS. They do not prove the end user may read or write. Do not accept authorId or permissions from the browser as the grant.

Permissions

read, create, reply, edit_own, delete_own, resolve, moderate. resolve also reopens. moderate tombstones any comment on that resource and stores the moderator as deletedBy. It does not edit someone else's text. Mint an explicit permissions array. Omitting it is validation_error. There is no default that includes moderate. A typical author mint is ["read","create","reply","edit_own","delete_own"].

When a token is required

  • Live: always, whether or not requireAuthorToken is set.
  • Test with requireAuthorToken: true: required.
  • Test with requireAuthorToken: false: optional. A present token is still verified.

When a token is present, author.id and viewerId must equal claim aid. A mismatch is forbidden. A malformed token, a bad signature, expiry, or a workspace or environment claim that does not match the API key is forbidden. A token that matches the key and names another app, tenant, resource type, or resource id is not_found with The requested resource was not found.

Mint

POST /api/v1/author-tokens with Authorization: Bearer and the secret key. Body: authorId, appId, tenantKey, resourceType, resourceId, permissions, optional mentions, optional expiresInSec. Environment comes from the key, not the body. Response 201: { data: { authorToken, expiresAt } }. The browser receives only authorToken.

Default lifetime is 300 seconds. Clamp is 60–86400. Pass expiresInSec: 300. The widget renews through renewAuthorToken when unverified exp is under 60 seconds away, and again when the server reports expiry, at most once every 30 seconds. Renewal failure keeps the composer text.

There is no revocation list. A token stays valid until exp. Maximum exposure is the minted TTL. Stop minting when access ends. Resource purge rejects new writes immediately, so a still-valid token cannot create content on a purged resource.

Worked route: Next.js and resource authorization.

Related: API keys · Mentions · Origins