fix(rpc): close identity-token fail-open and validation gaps

- importSubjectContext now rejects a non-string/empty selfApp before
  verifying. verifyJwt skips the audience check entirely when audience
  is undefined, so an unvalidated selfApp (the natural shape of
  currentAppName(): string | undefined) accepted every token from every
  app for every audience.
- exportSubjectContext now rejects a non-string/empty targetApp, so an
  array can no longer mint one token valid at multiple apps.
- Both directions now reject a present-but-non-string tenant id instead
  of silently dropping it (was: callee reads missing tenantId as
  global/unscoped -> cross-tenant exposure).
- importSubjectContext now requires exp to be present and independently
  bounds accepted token age via a new maxAge/ImportOptions.maxAgeSeconds
  (default 300s), so a caller cannot mint a long-lived token via a huge
  ttlSeconds and have it honoured indefinitely.
- SubjectContext.callerApp doc now states it is self-asserted (the
  signing secret is workspace-wide) and must never be an authz input.
- index.ts also exports the new ImportOptions type.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-05 14:26:14 +05:30
co-authored by Claude Opus 5
parent 1393a8a3b8
commit 83c99cc3e5
3 changed files with 100 additions and 10 deletions
+1 -1
View File
@@ -29,4 +29,4 @@ export {
importSubjectContext,
rpcSecret,
} from "./identity.ts";
export type { ExportOptions, SubjectContext } from "./identity.ts";
export type { ExportOptions, ImportOptions, SubjectContext } from "./identity.ts";