|
| 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