Operant Studio
OPER-5

feat(auth): per-user API tokens (not per-team bearers)

Band
LARGE

Body

Today auth is (a) NextAuth session cookie or (b) team-wide `LEDGER_BEARER_<TEAM>` env var. Neither is right for humans doing automation from their own laptops or scripts.

## Scope
- New `UserApiToken` table: `{id, userId, name, tokenHash, lastUsedAt, expiresAt?, revokedAt?, createdAt}`.
- Store SHA-256 of token, never plaintext.
- Settings page `/settings/tokens` for humans to mint, name, and revoke personal tokens.
- Mint flow shows the plaintext token exactly once, then only prefix + name.
- Token becomes a third `resolveActor` path in `apps/web/src/lib/auth.ts` — inherits user identity, respects all TeamMembership scopes and roles.
- Rate-limit + audit-log on every use.

## Verification
- Sweet mints a token in /settings/tokens.
- She curls `curl -H "Authorization: Bearer $HER_TOKEN" https://studio.operant.health/api/studio/portico/tasks`.
- She sees her user identity in AuditLog, scoped to Portico + Operant Studio (her memberships).
- She revokes it; next call returns 401.

Attachments

Loading attachments…

Comments

Loading comments…