inspector/core/auth/scopes.ts
Bob Dickinson a71e6d2012
Some checks failed
Run install, format, lint, build, and test on every push / build (push) Has been cancelled
Run install, format, lint, build, and test on every push / publish (push) Has been cancelled
Run install, format, lint, build, and test on every push / publish-github-container-registry (push) Has been cancelled
Auth hardening CI gaps + SDK consolidation: EMA leg 2 / scopes (#1527) (#1725)
Close #1527 acceptance gaps with automated tests (SEP-2468 iss, SEP-2207 offline_access, SEP-2351 discovery shapes, SEP-2352 AS-migration, EraNegotiationFailed→401 unwrap); lean EMA leg 2 and scope helpers on the v2 SDK; drop deprecated TS baseUrl. Reviewed LGTM.
2026-07-19 22:36:21 -04:00

51 lines
1.7 KiB
TypeScript

/**
* SEP-2350 scope helpers. Union / strict-superset algorithms come from
* `@modelcontextprotocol/client`; Inspector-only persistence helpers stay local.
*/
import {
computeScopeUnion as sdkComputeScopeUnion,
isStrictScopeSuperset as sdkIsStrictScopeSuperset,
} from "@modelcontextprotocol/client";
/** Union space-delimited scope strings (order-preserving, deduped). */
export const computeScopeUnion = sdkComputeScopeUnion;
/**
* Whether `union` contains a scope token not present in `current`.
* When the AS omits `scope` on the token response, `current` is empty and any
* non-empty union is a strict superset — step-up must re-authorize, not refresh.
*/
export const isStrictScopeSuperset = sdkIsStrictScopeSuperset;
/**
* Scope to persist after a successful token grant (RFC 6749 §5.1).
* When the AS returns `scope`, it is the authoritative full grant.
* When `scope` is omitted on success, granted equals what was requested.
*/
export function resolvePersistedScopeAfterGrant(
grantedScope: string | undefined,
requestedScope: string | undefined,
): string | undefined {
const granted = grantedScope?.trim();
if (granted) {
return granted;
}
const requested = requestedScope?.trim();
return requested || undefined;
}
/**
* Scope coverage for satisfaction checks: prefer the token's explicit grant;
* when omitted, fall back to stored scope (RFC implied grant on prior success).
*/
export function resolveEffectiveGrantedScope(
storedScope: string | undefined,
tokenScope: string | undefined,
): string | undefined {
const granted = tokenScope?.trim();
if (granted) {
return granted;
}
return computeScopeUnion(storedScope, tokenScope);
}