Skip to content

Commit 153141f

Browse files
committed
chore: changeset for the principal-session mint
Claude-Session: https://claude.ai/code/session_01QBUMRzs2CSSq7QCTU1gT2j Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3ec78fd commit 153141f

1 file changed

Lines changed: 30 additions & 0 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/plugin-auth': minor
4+
---
5+
6+
feat(spec,plugin-auth): a short-lived principal-session mint, `IAuthService.mintPrincipalSession`, implemented by `AuthManager`
7+
8+
Clause-②: yes (widening)
9+
10+
An in-process service can now act as the requesting user through a door that only accepts a session, such as a headless browser rendering a page the user may see, under the user's own principal and never a system one. Nothing is removed and no HTTP route is added.
11+
12+
- **`@objectstack/spec`** (`contracts`): an optional `IAuthService` member, `mintPrincipalSession(context, options?)`, its types `PrincipalSession`, `PrincipalSessionCookie` and `PrincipalSessionMintOptions`, and the constant `PRINCIPAL_SESSION_MAX_TTL_SECONDS` (`120`). The member is optional, so every existing `IAuthService` implementation compiles unchanged.
13+
- **`@objectstack/plugin-auth`**: `AuthManager.mintPrincipalSession(context, options?)`.
14+
15+
What the mint guarantees:
16+
17+
- **Human principals only, refused before anything is minted.** A context with no user, a system context, or a `principalKind` other than `human` gets `PERMISSION_DENIED` / `403`. So does a user row that is missing, the system user or banned. A user an authentication policy holds gets `403` with the policy's own code (`MFA_REQUIRED`, `PASSWORD_EXPIRED`, `PASSWORD_RESET_REQUIRED`), whether the posture rides on the context or is computed at the call. A `ttlSeconds` outside 1 to 120 gets `VALIDATION_ERROR` / `400`: it is refused, never clamped.
18+
- **Short and never renewed.** The session lives at most 120 seconds. Reading it never extends it, on the cookie lane, the bearer lane or the in-process session read alike.
19+
- **Revocable.** `revoke()` ends the session. Afterwards neither the token nor the cookie resolves one. It is bound to that session alone and safe to call twice, so call it in a `finally`.
20+
- **The deployment's own cookie.** The cookie carries the name and attributes of the plugin's session cookie, the cookie prefix and, on a secure deployment, `__Secure-` included. The session's active organization is the context's `tenantId`.
21+
22+
```ts
23+
const auth = ctx.getService<IAuthService>('auth');
24+
const session = await auth.mintPrincipalSession?.(context, { ttlSeconds: 60 });
25+
try {
26+
// send session.token as `Authorization: Bearer`, or set session.cookie in a browser
27+
} finally {
28+
await session?.revoke();
29+
}
30+
```

0 commit comments

Comments
 (0)