/** * OAuth flow interception. * * Wraps the original provider's OAuth login/refresh/getApiKey methods * to store and retrieve tokens from the credential backend instead of auth.json. */ import type { OAuthCredentials, OAuthLoginCallbacks } from "@mariozechner/pi-ai"; import { getOAuthProvider } from "@mariozechner/pi-ai/oauth"; import type { CredentialBackend, OAuthEntry } from "../types.js"; function oauthEntryToCredentials(entry: OAuthEntry): OAuthCredentials { return { access: entry.access, refresh: entry.refresh, expires: entry.expires, accountId: entry.accountId, }; } function credentialsToOAuthEntry(creds: OAuthCredentials): OAuthEntry { return { type: "oauth", access: creds.access, refresh: creds.refresh, expires: creds.expires, accountId: typeof creds.accountId === "string" ? creds.accountId : undefined, }; } /** * Create an OAuth config object that wraps the original provider's OAuth flow * but stores tokens in the vault backend. */ export function createOAuthWrapper( providerId: string, getBackend: () => CredentialBackend, ): { name: string; login: (callbacks: OAuthLoginCallbacks) => Promise; refreshToken: (credentials: OAuthCredentials) => Promise; getApiKey: (credentials: OAuthCredentials) => string; } | undefined { const originalOAuth = getOAuthProvider(providerId); if (!originalOAuth) { return undefined; } return { name: originalOAuth.name, async login(callbacks: OAuthLoginCallbacks): Promise { // Delegate the actual login flow to the original provider const credentials = await originalOAuth.login(callbacks); // Store the tokens in the vault backend const backend = getBackend(); await backend.set(providerId, credentialsToOAuthEntry(credentials)); return credentials; }, async refreshToken( credentials: OAuthCredentials, ): Promise { // Delegate refresh to the original provider const refreshed = await originalOAuth.refreshToken(credentials); // Store the refreshed tokens in the vault backend const backend = getBackend(); await backend.set(providerId, credentialsToOAuthEntry(refreshed)); return refreshed; }, getApiKey(credentials: OAuthCredentials): string { return originalOAuth.getApiKey(credentials); }, }; } /** * Load stored OAuth credentials from the vault backend. * Returns undefined if not stored or not an OAuth entry. */ export async function loadOAuthFromVault( providerId: string, backend: CredentialBackend, ): Promise { const entry = await backend.get(providerId); if (!entry || entry.type !== "oauth") { return undefined; } return oauthEntryToCredentials(entry); }