/** * Google identity resolver — Phase 3, slice 1 (see docs/PHASE3_IMPLEMENTATION_SPEC.md). * * Given a Stytch (organizationId, memberId), returns an OAuth2Client carrying * that user's current Google access token, which Stytch vaults and refreshes on * our behalf. This is the data-plane core of multi-user mode: the validated * Stytch token (slice 2) yields org + member, this resolves the per-user Google * client, and the Phase 1 `runWithAuth` hook scopes it to the request. * * Verified endpoint + response shape: scripts/stytch-spike.mjs confirmed * GET /v1/b2b/organizations/{org}/members/{member}/oauth_providers/google * returns { access_token, access_token_expires_in, scopes, ... } and that the * token works against the live GTM API. * * IMPORTANT: we never request `include_refresh_token`. Pulling the raw refresh * token would disable Stytch's automatic refresh (per Stytch docs). We only use * the short-lived access token and re-pull a fresh one as it nears expiry. */ import { OAuth2Client } from 'google-auth-library'; export interface ResolverConfig { /** Stytch project id (e.g. project-test-… / project-live-…). */ projectId: string; /** Stytch secret (server-only). */ secret: string; /** API base override; defaults are derived from the project id prefix. */ apiBase?: string; /** Clock injection for tests. */ now?: () => number; /** fetch injection for tests. */ fetchImpl?: typeof fetch; /** Seconds of headroom before access-token expiry that triggers a re-pull. */ refreshBufferSeconds?: number; /** * If set, the member's granted Google scopes must include at least one of * these, or `resolve()` throws {@link GoogleScopeError}. Matched by the last * path segment so a host-prefix difference doesn't cause a false negative. * Leave unset to skip the check (default). */ requiredAnyScopes?: string[]; /** * Upper bound on cached per-member entries. On the single-process hosted endpoint the cache would * otherwise grow without eviction as distinct members sign in over time, retaining their (short-lived) * access tokens + OAuth2Client instances forever. When the bound is hit, expired entries are dropped * first, then the least-recently-used. Default 5000. */ maxCacheEntries?: number; } /** * Thrown when the member's Stytch-vaulted Google grant is missing every scope * the server needs. Distinct from a transport/Stytch error so callers can turn * it into a 403 with an actionable "re-consent" message instead of a 502. */ export declare class GoogleScopeError extends Error { readonly grantedScopes: string[]; constructor(message: string, grantedScopes: string[]); } export interface GoogleIdentityResolver { /** Resolve (and cache) the per-user Google OAuth2Client for a member. */ resolve(organizationId: string, memberId: string): Promise; /** Number of cached members (for tests/metrics). */ cacheSize(): number; } /** Live projects talk to api.stytch.com; everything else is the test host. */ export declare function deriveApiBase(projectId: string): string; export declare function createGoogleIdentityResolver(cfg: ResolverConfig): GoogleIdentityResolver; //# sourceMappingURL=googleIdentityResolver.d.ts.map