Repository navigation
feat(auth): explicitly type sandbox JWTs with a compatible migration #2753
Description
Problem Statement
Sandbox admission JWTs currently use the generic JWT JOSE type (or may be untyped), while extension credentials use openshell-ext+jwt. PR #2638 prevents cross-domain replay by rejecting extension-token types at the sandbox authentication boundary and reserving the gateway sandbox audience, but sandbox credentials still lack their own explicit type.
An explicit sandbox token type adds defense in depth and enables the gateway to validate the sandbox trust domain independently of claims. Strict enforcement cannot be enabled immediately because supervisors may retain legacy tokens across a gateway upgrade, and sandbox JWTs may be configured as non-expiring.
Proposed Design
Introduce openshell-sandbox+jwt for gateway-minted sandbox admission tokens.
Phase 1 — compatible rollout:
- Define the sandbox token type in the gateway sandbox-authentication module rather than
openshell-extension-core. - Set
typ: openshell-sandbox+jwton every newly minted sandbox JWT. - Accept
openshell-sandbox+jwt, legacyJWT, and missingtypduring validation. - Continue to reject
openshell-ext+jwtunconditionally, as implemented by fix(security): authenticate extension services #2638. - Add tests for the new minting header, new-token authentication, legacy
JWTauthentication, untyped-token authentication, and extension-token rejection. - Document the compatibility window and expose enough diagnostics to determine whether legacy tokens are still presented.
Phase 2 — strict validation:
- Require
typ: openshell-sandbox+jwtexactly. - Remove legacy
JWTand untyped acceptance only after a defined cutover mechanism guarantees old credentials have been replaced. Token TTL alone is insufficient becausegateway_jwt.ttl_secs = 0permits non-expiring credentials. - Use either an explicit compatibility setting/deprecation cycle or a restart/refresh mechanism that reissues credentials for all active sandboxes before strict mode becomes the default.
Alternatives Considered
- Keep rejecting only
openshell-ext+jwt: this closes the known replay path but leaves sandbox credentials without a positive trust-domain discriminator. - Enforce the new type immediately: simpler validation, but it can break running supervisors holding tokens minted before a gateway upgrade.
- Put the constant in
openshell-extension-core: rejected because sandbox admission is gateway-internal authentication, not extension-facing functionality. - Use a separate signing key immediately: stronger trust-domain separation, but substantially broader than token typing and can remain a later key-rotation design.
Agent Investigation
Related work: #2623 and PR #2638.
SandboxJwtIssuer::mint currently constructs a generic EdDSA header and sets only kid; jsonwebtoken::Header::new supplies the legacy JWT type. SandboxJwtAuthenticator::validate_bearer now rejects openshell-ext+jwt before key fallback but otherwise accepts the legacy header shape. The gateway is both issuer and validator, while supervisors transport and may cache the opaque credential, making additive minting safe but immediate strict validation unsafe across rolling upgrades.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Aug 29, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.