@mcp-z/oauth-google 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/lib/dcr-router.js +15 -0
- package/dist/cjs/lib/dcr-router.js.map +1 -1
- package/dist/cjs/setup/config.js +3 -2
- package/dist/cjs/setup/config.js.map +1 -1
- package/dist/esm/lib/dcr-router.js +15 -0
- package/dist/esm/lib/dcr-router.js.map +1 -1
- package/dist/esm/setup/config.js +3 -2
- package/dist/esm/setup/config.js.map +1 -1
- package/package.json +13 -13
|
@@ -309,6 +309,21 @@ function _ts_generator(thisArg, body) {
|
|
|
309
309
|
function createDcrRouter(config) {
|
|
310
310
|
var router = _express.default.Router();
|
|
311
311
|
var store = config.store, issuerUrl = config.issuerUrl, baseUrl = config.baseUrl, scopesSupported = config.scopesSupported, clientConfig = config.clientConfig;
|
|
312
|
+
router.use('/mcp', function(req, res, next) {
|
|
313
|
+
var authHeader = req.headers.authorization || req.headers.Authorization;
|
|
314
|
+
var headerValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;
|
|
315
|
+
if (!headerValue || !headerValue.toLowerCase().startsWith('bearer ')) {
|
|
316
|
+
return res.status(401).set('WWW-Authenticate', 'Bearer resource_metadata="'.concat(baseUrl, '/.well-known/oauth-protected-resource"')).json({
|
|
317
|
+
jsonrpc: '2.0',
|
|
318
|
+
error: {
|
|
319
|
+
code: -32600,
|
|
320
|
+
message: 'Missing Authorization header. DCR mode requires bearer token.'
|
|
321
|
+
},
|
|
322
|
+
id: null
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
return next();
|
|
326
|
+
});
|
|
312
327
|
router.use(_express.default.json());
|
|
313
328
|
router.use(_express.default.urlencoded({
|
|
314
329
|
extended: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/lib/dcr-router.ts"],"sourcesContent":["/**\n * DCR Router - OAuth 2.0 Authorization Server\n *\n * Implements OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591)\n * and OAuth 2.0 Authorization Server endpoints (RFC 6749, RFC 8414, RFC 9728).\n *\n * Endpoints:\n * - GET /.well-known/oauth-authorization-server (RFC 8414 metadata)\n * - GET /.well-known/oauth-protected-resource (RFC 9728 metadata - root)\n * - GET /.well-known/oauth-protected-resource/mcp (RFC 9728 metadata - sub-path)\n * - POST /oauth/register (RFC 7591 client registration)\n * - GET /oauth/authorize (RFC 6749 authorization endpoint)\n * - POST /oauth/token (RFC 6749 token endpoint)\n * - POST /oauth/revoke (RFC 7009 token revocation)\n * - GET /oauth/verify (token verification for Resource Server)\n */\n\nimport type { ProviderTokens, RFC8414Metadata, RFC9728Metadata } from '@mcp-z/oauth';\nimport { createHash, randomUUID } from 'crypto';\nimport type { Request, Response } from 'express';\nimport express from 'express';\nimport type { Keyv } from 'keyv';\nimport { DcrOAuthProvider } from '../providers/dcr.ts';\nimport type { AccessToken, AuthorizationCode, OAuthClientConfig } from '../types.ts';\nimport * as dcrUtils from './dcr-utils.ts';\n\n/**\n * Configuration for DCR Router (self-hosted mode only)\n */\nexport interface DcrRouterConfig {\n /** Single Keyv store for all DCR data */\n store: Keyv;\n\n /** Authorization Server issuer URL */\n issuerUrl: string;\n\n /** Base URL for OAuth endpoints */\n baseUrl: string;\n\n /** Supported OAuth scopes */\n scopesSupported: string[];\n\n /** OAuth client configuration for upstream provider */\n clientConfig: OAuthClientConfig;\n}\n\n/**\n * Create DCR Router with OAuth 2.0 endpoints (self-hosted mode)\n *\n * For external mode (Auth0/Stitch), don't call this function - no router needed.\n * The server code should check DcrConfig.mode and only call this for 'self-hosted'.\n *\n * @param config - Router configuration\n * @returns Express router with OAuth endpoints\n */\nexport function createDcrRouter(config: DcrRouterConfig): express.Router {\n const router = express.Router();\n const { store, issuerUrl, baseUrl, scopesSupported, clientConfig } = config;\n\n router.use(express.json());\n router.use(express.urlencoded({ extended: true }));\n\n /**\n * OAuth Authorization Server Metadata (RFC 8414)\n * GET /.well-known/oauth-authorization-server\n */\n router.get('/.well-known/oauth-authorization-server', (_req: Request, res: Response) => {\n const metadata: RFC8414Metadata = {\n issuer: issuerUrl,\n authorization_endpoint: `${baseUrl}/oauth/authorize`,\n token_endpoint: `${baseUrl}/oauth/token`,\n registration_endpoint: `${baseUrl}/oauth/register`,\n revocation_endpoint: `${baseUrl}/oauth/revoke`,\n scopes_supported: scopesSupported,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],\n code_challenge_methods_supported: ['S256', 'plain'],\n service_documentation: `${baseUrl}/docs`,\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Root)\n * GET /.well-known/oauth-protected-resource\n */\n router.get('/.well-known/oauth-protected-resource', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: baseUrl,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Sub-path /mcp)\n * GET /.well-known/oauth-protected-resource/mcp\n */\n router.get('/.well-known/oauth-protected-resource/mcp', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * Dynamic Client Registration (RFC 7591)\n * POST /oauth/register\n */\n router.post('/oauth/register', async (req: Request, res: Response) => {\n try {\n const registrationRequest = req.body;\n const client = await dcrUtils.registerClient(store, registrationRequest);\n res.status(201).json(client);\n } catch (error) {\n res.status(400).json({\n error: 'invalid_client_metadata',\n error_description: error instanceof Error ? error.message : 'Invalid registration request',\n });\n }\n });\n\n /**\n * OAuth Authorization Endpoint (RFC 6749 Section 3.1)\n * GET /oauth/authorize\n *\n * Initiates Google OAuth flow, then generates DCR authorization code\n */\n router.get('/oauth/authorize', async (req: Request, res: Response) => {\n const { response_type, client_id, redirect_uri, scope = '', state = '', code_challenge, code_challenge_method } = req.query;\n\n if (response_type !== 'code') {\n return res.status(400).json({\n error: 'unsupported_response_type',\n error_description: 'Only response_type=code is supported',\n });\n }\n\n if (!client_id || typeof client_id !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'client_id is required',\n });\n }\n\n if (!redirect_uri || typeof redirect_uri !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'redirect_uri is required',\n });\n }\n\n const client = await dcrUtils.getClient(store, client_id);\n if (!client) {\n return res.status(400).json({\n error: 'invalid_client',\n error_description: 'Unknown client_id',\n });\n }\n\n const isValidRedirect = await dcrUtils.validateRedirectUri(store, client_id, redirect_uri);\n if (!isValidRedirect) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid redirect_uri',\n });\n }\n\n const googleState = randomUUID();\n const dcrRequestState = {\n client_id,\n redirect_uri,\n scope: typeof scope === 'string' ? scope : '',\n state: typeof state === 'string' ? state : undefined,\n code_challenge: typeof code_challenge === 'string' ? code_challenge : undefined,\n code_challenge_method: typeof code_challenge_method === 'string' ? code_challenge_method : undefined,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await store.set(`dcr:google-state:${googleState}`, dcrRequestState, 600000);\n\n const googleAuthUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');\n googleAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n googleAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n googleAuthUrl.searchParams.set('response_type', 'code');\n googleAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n googleAuthUrl.searchParams.set('state', googleState);\n googleAuthUrl.searchParams.set('access_type', 'offline');\n googleAuthUrl.searchParams.set('prompt', 'consent');\n\n return res.redirect(googleAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles OAuth callback from Google, exchanges authorization code for tokens,\n * and redirects back to client with DCR authorization code.\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: googleCode, state: googleState, error } = req.query;\n\n if (error) {\n return res.status(400).json({\n error: typeof error === 'string' ? error : 'access_denied',\n error_description: 'Google OAuth authorization failed',\n });\n }\n\n if (!googleCode || typeof googleCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing authorization code from Google',\n });\n }\n\n if (!googleState || typeof googleState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing state parameter',\n });\n }\n\n const dcrRequestState = await store.get(`dcr:google-state:${googleState}`);\n if (!dcrRequestState) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid or expired state parameter',\n });\n }\n\n await store.delete(`dcr:google-state:${googleState}`);\n\n if (Date.now() > dcrRequestState.expires_at) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'DCR request state expired',\n });\n }\n\n const tokenUrl = 'https://oauth2.googleapis.com/token';\n // Build token params - only include client_secret for confidential clients\n // Public clients (Desktop apps) should NOT send client_secret at all\n const tokenParamsObj: Record<string, string> = {\n code: googleCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n grant_type: 'authorization_code',\n };\n if (clientConfig.clientSecret) {\n tokenParamsObj.client_secret = clientConfig.clientSecret;\n }\n const tokenParams = new URLSearchParams(tokenParamsObj);\n\n const tokenResponse = await fetch(tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: tokenParams.toString(),\n });\n\n if (!tokenResponse.ok) {\n const errorText = await tokenResponse.text();\n return res.status(400).json({\n error: 'server_error',\n error_description: `Failed to exchange Google authorization code: ${errorText}`,\n });\n }\n\n const tokenData = (await tokenResponse.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope: string;\n };\n\n // Create provider tokens from Google response\n const providerTokens: ProviderTokens = {\n accessToken: tokenData.access_token,\n ...(tokenData.refresh_token && { refreshToken: tokenData.refresh_token }),\n expiresAt: Date.now() + tokenData.expires_in * 1000,\n scope: tokenData.scope,\n };\n\n const dcrCode = randomUUID();\n const authCode: AuthorizationCode = {\n code: dcrCode,\n client_id: dcrRequestState.client_id,\n redirect_uri: dcrRequestState.redirect_uri,\n scope: dcrRequestState.scope,\n ...(dcrRequestState.code_challenge && { code_challenge: dcrRequestState.code_challenge }),\n ...(dcrRequestState.code_challenge_method && { code_challenge_method: dcrRequestState.code_challenge_method }),\n providerTokens,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await dcrUtils.setAuthCode(store, dcrCode, authCode);\n\n const clientRedirectUrl = new URL(dcrRequestState.redirect_uri);\n clientRedirectUrl.searchParams.set('code', dcrCode);\n if (dcrRequestState.state) {\n clientRedirectUrl.searchParams.set('state', dcrRequestState.state);\n }\n\n return res.redirect(clientRedirectUrl.toString());\n });\n\n /**\n * OAuth Token Endpoint (RFC 6749 Section 3.2)\n * POST /oauth/token\n */\n router.post('/oauth/token', async (req: Request, res: Response) => {\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n const authHeader = req.headers.authorization;\n if (authHeader && authHeader.startsWith('Basic ')) {\n const base64Credentials = authHeader.substring(6);\n const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8');\n const [id, secret] = credentials.split(':');\n client_id = id;\n client_secret = secret;\n }\n\n const { grant_type, code, redirect_uri, refresh_token, code_verifier } = req.body;\n\n if (!grant_type) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'grant_type is required',\n });\n }\n\n if (grant_type === 'authorization_code') {\n if (!code || !client_id || !redirect_uri) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code, client_id, and redirect_uri are required',\n });\n }\n\n // Validate client credentials\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const authCode = await dcrUtils.getAuthCode(store, code);\n if (!authCode) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid or expired authorization code',\n });\n }\n\n if (authCode.client_id !== client_id || authCode.redirect_uri !== redirect_uri) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code mismatch',\n });\n }\n\n if (Date.now() > authCode.expires_at) {\n await dcrUtils.deleteAuthCode(store, code);\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code expired',\n });\n }\n\n if (authCode.code_challenge) {\n if (!code_verifier) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code_verifier is required for PKCE',\n });\n }\n\n const method = authCode.code_challenge_method ?? 'plain';\n const computedChallenge = method === 'S256' ? createHash('sha256').update(code_verifier).digest('base64url') : code_verifier;\n\n if (computedChallenge !== authCode.code_challenge) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid code_verifier',\n });\n }\n }\n\n await dcrUtils.deleteAuthCode(store, code);\n\n const accessToken = randomUUID();\n const refreshTokenValue = randomUUID();\n\n const tokenData: AccessToken = {\n access_token: accessToken,\n token_type: 'Bearer',\n expires_in: 3600,\n refresh_token: refreshTokenValue,\n scope: authCode.scope,\n client_id,\n providerTokens: authCode.providerTokens,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, accessToken, tokenData);\n await dcrUtils.setRefreshToken(store, refreshTokenValue, tokenData);\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n return res.json({\n access_token: tokenData.access_token,\n token_type: tokenData.token_type,\n expires_in: tokenData.expires_in,\n refresh_token: tokenData.refresh_token,\n scope: tokenData.scope,\n });\n }\n if (grant_type === 'refresh_token') {\n if (!refresh_token || !client_id) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'refresh_token and client_id are required',\n });\n }\n\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const tokenData = await dcrUtils.getRefreshToken(store, refresh_token);\n if (!tokenData || tokenData.client_id !== client_id) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid refresh token',\n });\n }\n\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Google tokens\n const provider = new DcrOAuthProvider({\n ...clientConfig,\n scope: tokenData.scope,\n verifyEndpoint: `${baseUrl}/oauth/verify`,\n logger: {\n info: console.log,\n error: console.error,\n warn: console.warn,\n debug: () => {},\n },\n });\n\n // Refresh the Google access token\n refreshedProviderTokens = await provider.refreshAccessToken(tokenData.providerTokens.refreshToken);\n } catch (error) {\n // If refresh fails, continue with existing tokens (they may still be valid)\n console.warn('Provider token refresh failed, using existing tokens:', error instanceof Error ? error.message : String(error));\n }\n }\n\n const newAccessToken = randomUUID();\n const newTokenData: AccessToken = {\n ...tokenData,\n access_token: newAccessToken,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, newAccessToken, newTokenData);\n await dcrUtils.setProviderTokens(store, newAccessToken, refreshedProviderTokens);\n\n return res.json({\n access_token: newTokenData.access_token,\n token_type: newTokenData.token_type,\n expires_in: newTokenData.expires_in,\n scope: newTokenData.scope,\n });\n }\n return res.status(400).json({\n error: 'unsupported_grant_type',\n error_description: 'Only authorization_code and refresh_token grants are supported',\n });\n });\n\n /**\n * OAuth Token Revocation (RFC 7009)\n * POST /oauth/revoke\n */\n router.post('/oauth/revoke', async (req: Request, res: Response) => {\n const { token, token_type_hint, client_id, client_secret } = req.body;\n\n if (!token) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'token is required',\n });\n }\n\n if (client_id && client_secret) {\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret);\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n }\n\n if (token_type_hint === 'refresh_token') {\n await dcrUtils.deleteRefreshToken(store, token);\n } else if (token_type_hint === 'access_token') {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n } else {\n // No hint - try both\n await dcrUtils.deleteRefreshToken(store, token);\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n }\n\n return res.status(200).send();\n });\n\n /**\n * Token Verification Endpoint\n * GET /oauth/verify\n *\n * Validates bearer tokens for Resource Server.\n * Returns AuthInfo with provider tokens for stateless DCR pattern.\n */\n router.get('/oauth/verify', async (req: Request, res: Response) => {\n const authHeader = req.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n error: 'invalid_request',\n error_description: 'Missing or invalid Authorization header',\n });\n }\n\n const token = authHeader.substring(7);\n const tokenData = await dcrUtils.getAccessToken(store, token);\n\n if (!tokenData) {\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Unknown or expired access token',\n });\n }\n\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Access token has expired',\n });\n }\n\n const authInfo = {\n token,\n clientId: tokenData.client_id,\n scopes: tokenData.scope ? tokenData.scope.split(' ') : [],\n expiresAt,\n providerTokens: tokenData.providerTokens,\n };\n\n return res.json(authInfo);\n });\n\n /**\n * Debug endpoint to list registered clients (development only)\n */\n router.get('/debug/clients', async (_req: Request, res: Response) => {\n const clients = await dcrUtils.listClients(store);\n return res.json(clients);\n });\n\n return router;\n}\n"],"names":["createDcrRouter","config","router","express","Router","store","issuerUrl","baseUrl","scopesSupported","clientConfig","use","json","urlencoded","extended","get","_req","res","metadata","issuer","authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","scopes_supported","response_types_supported","grant_types_supported","token_endpoint_auth_methods_supported","code_challenge_methods_supported","service_documentation","resource","authorization_servers","bearer_methods_supported","post","req","registrationRequest","client","error","body","dcrUtils","registerClient","status","error_description","Error","message","response_type","client_id","redirect_uri","scope","state","code_challenge","code_challenge_method","isValidRedirect","googleState","dcrRequestState","googleAuthUrl","query","getClient","validateRedirectUri","randomUUID","undefined","created_at","Date","now","expires_at","set","URL","searchParams","clientId","redirect","toString","googleCode","tokenUrl","tokenParamsObj","tokenParams","tokenResponse","errorText","tokenData","providerTokens","dcrCode","authCode","clientRedirectUrl","code","delete","grant_type","clientSecret","client_secret","URLSearchParams","fetch","method","headers","ok","text","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","setAuthCode","authHeader","base64Credentials","credentials","id","secret","code_verifier","isValidClient","computedChallenge","refreshTokenValue","refreshedProviderTokens","provider","newAccessToken","newTokenData","authorization","startsWith","substring","Buffer","from","split","validateClient","getAuthCode","deleteAuthCode","createHash","update","digest","token_type","setAccessToken","setRefreshToken","setProviderTokens","getRefreshToken","DcrOAuthProvider","verifyEndpoint","logger","info","console","log","warn","debug","refreshAccessToken","String","token","token_type_hint","deleteRefreshToken","deleteAccessToken","deleteProviderTokens","send","authInfo","getAccessToken","scopes","clients","listClients"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/lib/dcr-router.ts"],"sourcesContent":["/**\n * DCR Router - OAuth 2.0 Authorization Server\n *\n * Implements OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591)\n * and OAuth 2.0 Authorization Server endpoints (RFC 6749, RFC 8414, RFC 9728).\n *\n * Endpoints:\n * - GET /.well-known/oauth-authorization-server (RFC 8414 metadata)\n * - GET /.well-known/oauth-protected-resource (RFC 9728 metadata - root)\n * - GET /.well-known/oauth-protected-resource/mcp (RFC 9728 metadata - sub-path)\n * - POST /oauth/register (RFC 7591 client registration)\n * - GET /oauth/authorize (RFC 6749 authorization endpoint)\n * - POST /oauth/token (RFC 6749 token endpoint)\n * - POST /oauth/revoke (RFC 7009 token revocation)\n * - GET /oauth/verify (token verification for Resource Server)\n */\n\nimport type { ProviderTokens, RFC8414Metadata, RFC9728Metadata } from '@mcp-z/oauth';\nimport { createHash, randomUUID } from 'crypto';\nimport type { Request, Response } from 'express';\nimport express from 'express';\nimport type { Keyv } from 'keyv';\nimport { DcrOAuthProvider } from '../providers/dcr.ts';\nimport type { AccessToken, AuthorizationCode, OAuthClientConfig } from '../types.ts';\nimport * as dcrUtils from './dcr-utils.ts';\n\n/**\n * Configuration for DCR Router (self-hosted mode only)\n */\nexport interface DcrRouterConfig {\n /** Single Keyv store for all DCR data */\n store: Keyv;\n\n /** Authorization Server issuer URL */\n issuerUrl: string;\n\n /** Base URL for OAuth endpoints */\n baseUrl: string;\n\n /** Supported OAuth scopes */\n scopesSupported: string[];\n\n /** OAuth client configuration for upstream provider */\n clientConfig: OAuthClientConfig;\n}\n\n/**\n * Create DCR Router with OAuth 2.0 endpoints (self-hosted mode)\n *\n * For external mode (Auth0/Stitch), don't call this function - no router needed.\n * The server code should check DcrConfig.mode and only call this for 'self-hosted'.\n *\n * @param config - Router configuration\n * @returns Express router with OAuth endpoints\n */\nexport function createDcrRouter(config: DcrRouterConfig): express.Router {\n const router = express.Router();\n const { store, issuerUrl, baseUrl, scopesSupported, clientConfig } = config;\n\n router.use('/mcp', (req: Request, res: Response, next) => {\n const authHeader = req.headers.authorization || req.headers.Authorization;\n const headerValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;\n\n if (!headerValue || !headerValue.toLowerCase().startsWith('bearer ')) {\n return res\n .status(401)\n .set('WWW-Authenticate', `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`)\n .json({\n jsonrpc: '2.0',\n error: {\n code: -32600,\n message: 'Missing Authorization header. DCR mode requires bearer token.',\n },\n id: null,\n });\n }\n\n return next();\n });\n\n router.use(express.json());\n router.use(express.urlencoded({ extended: true }));\n\n /**\n * OAuth Authorization Server Metadata (RFC 8414)\n * GET /.well-known/oauth-authorization-server\n */\n router.get('/.well-known/oauth-authorization-server', (_req: Request, res: Response) => {\n const metadata: RFC8414Metadata = {\n issuer: issuerUrl,\n authorization_endpoint: `${baseUrl}/oauth/authorize`,\n token_endpoint: `${baseUrl}/oauth/token`,\n registration_endpoint: `${baseUrl}/oauth/register`,\n revocation_endpoint: `${baseUrl}/oauth/revoke`,\n scopes_supported: scopesSupported,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],\n code_challenge_methods_supported: ['S256', 'plain'],\n service_documentation: `${baseUrl}/docs`,\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Root)\n * GET /.well-known/oauth-protected-resource\n */\n router.get('/.well-known/oauth-protected-resource', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: baseUrl,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Sub-path /mcp)\n * GET /.well-known/oauth-protected-resource/mcp\n */\n router.get('/.well-known/oauth-protected-resource/mcp', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * Dynamic Client Registration (RFC 7591)\n * POST /oauth/register\n */\n router.post('/oauth/register', async (req: Request, res: Response) => {\n try {\n const registrationRequest = req.body;\n const client = await dcrUtils.registerClient(store, registrationRequest);\n res.status(201).json(client);\n } catch (error) {\n res.status(400).json({\n error: 'invalid_client_metadata',\n error_description: error instanceof Error ? error.message : 'Invalid registration request',\n });\n }\n });\n\n /**\n * OAuth Authorization Endpoint (RFC 6749 Section 3.1)\n * GET /oauth/authorize\n *\n * Initiates Google OAuth flow, then generates DCR authorization code\n */\n router.get('/oauth/authorize', async (req: Request, res: Response) => {\n const { response_type, client_id, redirect_uri, scope = '', state = '', code_challenge, code_challenge_method } = req.query;\n\n if (response_type !== 'code') {\n return res.status(400).json({\n error: 'unsupported_response_type',\n error_description: 'Only response_type=code is supported',\n });\n }\n\n if (!client_id || typeof client_id !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'client_id is required',\n });\n }\n\n if (!redirect_uri || typeof redirect_uri !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'redirect_uri is required',\n });\n }\n\n const client = await dcrUtils.getClient(store, client_id);\n if (!client) {\n return res.status(400).json({\n error: 'invalid_client',\n error_description: 'Unknown client_id',\n });\n }\n\n const isValidRedirect = await dcrUtils.validateRedirectUri(store, client_id, redirect_uri);\n if (!isValidRedirect) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid redirect_uri',\n });\n }\n\n const googleState = randomUUID();\n const dcrRequestState = {\n client_id,\n redirect_uri,\n scope: typeof scope === 'string' ? scope : '',\n state: typeof state === 'string' ? state : undefined,\n code_challenge: typeof code_challenge === 'string' ? code_challenge : undefined,\n code_challenge_method: typeof code_challenge_method === 'string' ? code_challenge_method : undefined,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await store.set(`dcr:google-state:${googleState}`, dcrRequestState, 600000);\n\n const googleAuthUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');\n googleAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n googleAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n googleAuthUrl.searchParams.set('response_type', 'code');\n googleAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n googleAuthUrl.searchParams.set('state', googleState);\n googleAuthUrl.searchParams.set('access_type', 'offline');\n googleAuthUrl.searchParams.set('prompt', 'consent');\n\n return res.redirect(googleAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles OAuth callback from Google, exchanges authorization code for tokens,\n * and redirects back to client with DCR authorization code.\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: googleCode, state: googleState, error } = req.query;\n\n if (error) {\n return res.status(400).json({\n error: typeof error === 'string' ? error : 'access_denied',\n error_description: 'Google OAuth authorization failed',\n });\n }\n\n if (!googleCode || typeof googleCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing authorization code from Google',\n });\n }\n\n if (!googleState || typeof googleState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing state parameter',\n });\n }\n\n const dcrRequestState = await store.get(`dcr:google-state:${googleState}`);\n if (!dcrRequestState) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid or expired state parameter',\n });\n }\n\n await store.delete(`dcr:google-state:${googleState}`);\n\n if (Date.now() > dcrRequestState.expires_at) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'DCR request state expired',\n });\n }\n\n const tokenUrl = 'https://oauth2.googleapis.com/token';\n // Build token params - only include client_secret for confidential clients\n // Public clients (Desktop apps) should NOT send client_secret at all\n const tokenParamsObj: Record<string, string> = {\n code: googleCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n grant_type: 'authorization_code',\n };\n if (clientConfig.clientSecret) {\n tokenParamsObj.client_secret = clientConfig.clientSecret;\n }\n const tokenParams = new URLSearchParams(tokenParamsObj);\n\n const tokenResponse = await fetch(tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: tokenParams.toString(),\n });\n\n if (!tokenResponse.ok) {\n const errorText = await tokenResponse.text();\n return res.status(400).json({\n error: 'server_error',\n error_description: `Failed to exchange Google authorization code: ${errorText}`,\n });\n }\n\n const tokenData = (await tokenResponse.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope: string;\n };\n\n // Create provider tokens from Google response\n const providerTokens: ProviderTokens = {\n accessToken: tokenData.access_token,\n ...(tokenData.refresh_token && { refreshToken: tokenData.refresh_token }),\n expiresAt: Date.now() + tokenData.expires_in * 1000,\n scope: tokenData.scope,\n };\n\n const dcrCode = randomUUID();\n const authCode: AuthorizationCode = {\n code: dcrCode,\n client_id: dcrRequestState.client_id,\n redirect_uri: dcrRequestState.redirect_uri,\n scope: dcrRequestState.scope,\n ...(dcrRequestState.code_challenge && { code_challenge: dcrRequestState.code_challenge }),\n ...(dcrRequestState.code_challenge_method && { code_challenge_method: dcrRequestState.code_challenge_method }),\n providerTokens,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await dcrUtils.setAuthCode(store, dcrCode, authCode);\n\n const clientRedirectUrl = new URL(dcrRequestState.redirect_uri);\n clientRedirectUrl.searchParams.set('code', dcrCode);\n if (dcrRequestState.state) {\n clientRedirectUrl.searchParams.set('state', dcrRequestState.state);\n }\n\n return res.redirect(clientRedirectUrl.toString());\n });\n\n /**\n * OAuth Token Endpoint (RFC 6749 Section 3.2)\n * POST /oauth/token\n */\n router.post('/oauth/token', async (req: Request, res: Response) => {\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n const authHeader = req.headers.authorization;\n if (authHeader && authHeader.startsWith('Basic ')) {\n const base64Credentials = authHeader.substring(6);\n const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8');\n const [id, secret] = credentials.split(':');\n client_id = id;\n client_secret = secret;\n }\n\n const { grant_type, code, redirect_uri, refresh_token, code_verifier } = req.body;\n\n if (!grant_type) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'grant_type is required',\n });\n }\n\n if (grant_type === 'authorization_code') {\n if (!code || !client_id || !redirect_uri) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code, client_id, and redirect_uri are required',\n });\n }\n\n // Validate client credentials\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const authCode = await dcrUtils.getAuthCode(store, code);\n if (!authCode) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid or expired authorization code',\n });\n }\n\n if (authCode.client_id !== client_id || authCode.redirect_uri !== redirect_uri) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code mismatch',\n });\n }\n\n if (Date.now() > authCode.expires_at) {\n await dcrUtils.deleteAuthCode(store, code);\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code expired',\n });\n }\n\n if (authCode.code_challenge) {\n if (!code_verifier) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code_verifier is required for PKCE',\n });\n }\n\n const method = authCode.code_challenge_method ?? 'plain';\n const computedChallenge = method === 'S256' ? createHash('sha256').update(code_verifier).digest('base64url') : code_verifier;\n\n if (computedChallenge !== authCode.code_challenge) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid code_verifier',\n });\n }\n }\n\n await dcrUtils.deleteAuthCode(store, code);\n\n const accessToken = randomUUID();\n const refreshTokenValue = randomUUID();\n\n const tokenData: AccessToken = {\n access_token: accessToken,\n token_type: 'Bearer',\n expires_in: 3600,\n refresh_token: refreshTokenValue,\n scope: authCode.scope,\n client_id,\n providerTokens: authCode.providerTokens,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, accessToken, tokenData);\n await dcrUtils.setRefreshToken(store, refreshTokenValue, tokenData);\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n return res.json({\n access_token: tokenData.access_token,\n token_type: tokenData.token_type,\n expires_in: tokenData.expires_in,\n refresh_token: tokenData.refresh_token,\n scope: tokenData.scope,\n });\n }\n if (grant_type === 'refresh_token') {\n if (!refresh_token || !client_id) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'refresh_token and client_id are required',\n });\n }\n\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const tokenData = await dcrUtils.getRefreshToken(store, refresh_token);\n if (!tokenData || tokenData.client_id !== client_id) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid refresh token',\n });\n }\n\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Google tokens\n const provider = new DcrOAuthProvider({\n ...clientConfig,\n scope: tokenData.scope,\n verifyEndpoint: `${baseUrl}/oauth/verify`,\n logger: {\n info: console.log,\n error: console.error,\n warn: console.warn,\n debug: () => {},\n },\n });\n\n // Refresh the Google access token\n refreshedProviderTokens = await provider.refreshAccessToken(tokenData.providerTokens.refreshToken);\n } catch (error) {\n // If refresh fails, continue with existing tokens (they may still be valid)\n console.warn('Provider token refresh failed, using existing tokens:', error instanceof Error ? error.message : String(error));\n }\n }\n\n const newAccessToken = randomUUID();\n const newTokenData: AccessToken = {\n ...tokenData,\n access_token: newAccessToken,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, newAccessToken, newTokenData);\n await dcrUtils.setProviderTokens(store, newAccessToken, refreshedProviderTokens);\n\n return res.json({\n access_token: newTokenData.access_token,\n token_type: newTokenData.token_type,\n expires_in: newTokenData.expires_in,\n scope: newTokenData.scope,\n });\n }\n return res.status(400).json({\n error: 'unsupported_grant_type',\n error_description: 'Only authorization_code and refresh_token grants are supported',\n });\n });\n\n /**\n * OAuth Token Revocation (RFC 7009)\n * POST /oauth/revoke\n */\n router.post('/oauth/revoke', async (req: Request, res: Response) => {\n const { token, token_type_hint, client_id, client_secret } = req.body;\n\n if (!token) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'token is required',\n });\n }\n\n if (client_id && client_secret) {\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret);\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n }\n\n if (token_type_hint === 'refresh_token') {\n await dcrUtils.deleteRefreshToken(store, token);\n } else if (token_type_hint === 'access_token') {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n } else {\n // No hint - try both\n await dcrUtils.deleteRefreshToken(store, token);\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n }\n\n return res.status(200).send();\n });\n\n /**\n * Token Verification Endpoint\n * GET /oauth/verify\n *\n * Validates bearer tokens for Resource Server.\n * Returns AuthInfo with provider tokens for stateless DCR pattern.\n */\n router.get('/oauth/verify', async (req: Request, res: Response) => {\n const authHeader = req.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n error: 'invalid_request',\n error_description: 'Missing or invalid Authorization header',\n });\n }\n\n const token = authHeader.substring(7);\n const tokenData = await dcrUtils.getAccessToken(store, token);\n\n if (!tokenData) {\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Unknown or expired access token',\n });\n }\n\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Access token has expired',\n });\n }\n\n const authInfo = {\n token,\n clientId: tokenData.client_id,\n scopes: tokenData.scope ? tokenData.scope.split(' ') : [],\n expiresAt,\n providerTokens: tokenData.providerTokens,\n };\n\n return res.json(authInfo);\n });\n\n /**\n * Debug endpoint to list registered clients (development only)\n */\n router.get('/debug/clients', async (_req: Request, res: Response) => {\n const clients = await dcrUtils.listClients(store);\n return res.json(clients);\n });\n\n return router;\n}\n"],"names":["createDcrRouter","config","router","express","Router","store","issuerUrl","baseUrl","scopesSupported","clientConfig","use","req","res","next","authHeader","headers","authorization","Authorization","headerValue","Array","isArray","toLowerCase","startsWith","status","set","json","jsonrpc","error","code","message","id","urlencoded","extended","get","_req","metadata","issuer","authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","scopes_supported","response_types_supported","grant_types_supported","token_endpoint_auth_methods_supported","code_challenge_methods_supported","service_documentation","resource","authorization_servers","bearer_methods_supported","post","registrationRequest","client","body","dcrUtils","registerClient","error_description","Error","response_type","client_id","redirect_uri","scope","state","code_challenge","code_challenge_method","isValidRedirect","googleState","dcrRequestState","googleAuthUrl","query","getClient","validateRedirectUri","randomUUID","undefined","created_at","Date","now","expires_at","URL","searchParams","clientId","redirect","toString","googleCode","tokenUrl","tokenParamsObj","tokenParams","tokenResponse","errorText","tokenData","providerTokens","dcrCode","authCode","clientRedirectUrl","delete","grant_type","clientSecret","client_secret","URLSearchParams","fetch","method","ok","text","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","setAuthCode","base64Credentials","credentials","secret","code_verifier","isValidClient","computedChallenge","refreshTokenValue","refreshedProviderTokens","provider","newAccessToken","newTokenData","substring","Buffer","from","split","validateClient","getAuthCode","deleteAuthCode","createHash","update","digest","token_type","setAccessToken","setRefreshToken","setProviderTokens","getRefreshToken","DcrOAuthProvider","verifyEndpoint","logger","info","console","log","warn","debug","refreshAccessToken","String","token","token_type_hint","deleteRefreshToken","deleteAccessToken","deleteProviderTokens","send","authInfo","getAccessToken","scopes","clients","listClients"],"mappings":"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"}
|
package/dist/cjs/setup/config.js
CHANGED
|
@@ -150,9 +150,10 @@ function parseConfig(args, env, transport) {
|
|
|
150
150
|
if (redirectUri && transport === 'stdio') {
|
|
151
151
|
throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');
|
|
152
152
|
}
|
|
153
|
-
|
|
153
|
+
if (typeof values.headless === 'string') throw new Error('Use --headless or --no-headless (do not pass a value)');
|
|
154
|
+
var cliHeadless = values['no-headless'] ? false : values.headless === true ? true : undefined;
|
|
154
155
|
var envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;
|
|
155
|
-
var headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined;
|
|
156
|
+
var headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined;
|
|
156
157
|
var clientId = requiredEnv('GOOGLE_CLIENT_ID');
|
|
157
158
|
var clientSecret = env.GOOGLE_CLIENT_SECRET;
|
|
158
159
|
var serviceAccountKeyFile;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/setup/config.ts"],"sourcesContent":["/**\n * Google OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Google OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { resolve } from 'path';\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for direct imports from config.ts\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'service-account' | 'dcr';\n\n/**\n * Parse auth mode string into auth mode.\n *\n * @param value - Auth mode string ('loopback-oauth', 'service-account', or 'dcr')\n * @returns Parsed auth mode\n * @throws Error if value is invalid\n *\n * @example Valid formats\n * ```typescript\n * parseAuthMode('loopback-oauth') // { auth: 'loopback-oauth' }\n * parseAuthMode('service-account') // { auth: 'service-account' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n if (value !== 'loopback-oauth' && value !== 'service-account' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, service-account, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * @typedef {('stdio' | 'http')} TransportType\n * @property {'stdio'} stdio - Standard input/output transport for CLI applications\n * @property {'http'} http - HTTP transport for web-based applications\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Google OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: Auth mode ('loopback-oauth' | 'service-account' | 'dcr')\n * - Default: 'loopback-oauth' (if flag is omitted)\n * - --headless: Disable browser opening for OAuth flow (default: false, true in test env)\n * - --redirect-uri: Override OAuth redirect URI (default: ephemeral loopback)\n * - --service-account-key-file: Service account key file path (required for service-account mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - AUTH_MODE: Auth mode (same format as --auth flag)\n * - HEADLESS: Headless mode flag ('true' to enable)\n * - REDIRECT_URI: OAuth redirect URI (overridden by --redirect-uri CLI flag)\n * - GOOGLE_SERVICE_ACCOUNT_KEY_FILE: Service account key file (for service-account mode)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param transport - Optional transport type. If 'stdio' and auth mode is 'dcr', throws an error.\n * See {@link TransportType} for valid values.\n * @returns Parsed Google OAuth configuration\n * @throws Error if required environment variables are missing, values are invalid, or DCR is used with stdio transport\n *\n * @example Default mode (no flags)\n * ```typescript\n * const config = parseConfig(process.argv, process.env);\n * // { auth: 'loopback-oauth' }\n * ```\n *\n * @example Override auth mode\n * ```typescript\n * parseConfig(['--auth=loopback-oauth'], process.env);\n * parseConfig(['--auth=service-account'], process.env);\n * parseConfig(['--auth=dcr'], process.env);\n * ```\n *\n * @example With transport validation\n * ```typescript\n * parseConfig(['--auth=dcr'], process.env, 'http'); // OK\n * parseConfig(['--auth=dcr'], process.env, 'stdio'); // Throws error\n * ```\n *\n * Valid auth modes:\n * - loopback-oauth (default)\n * - service-account\n * - dcr (HTTP transport only)\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>, transport?: TransportType): OAuthConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for Google OAuth`);\n }\n return value;\n }\n\n // Parse CLI arguments\n const { values } = parseArgs({\n args,\n options: {\n auth: { type: 'string' },\n headless: { type: 'boolean' },\n 'redirect-uri': { type: 'string' },\n 'service-account-key-file': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const authArg = typeof values.auth === 'string' ? values.auth : undefined;\n const envAuthMode = env.AUTH_MODE;\n const mode = authArg || envAuthMode;\n\n let auth: AuthMode;\n\n if (mode) {\n const parsed = parseAuthMode(mode);\n auth = parsed.auth;\n } else {\n // DEFAULT: No flags provided, use loopback-oauth\n auth = 'loopback-oauth';\n }\n\n // Validate: DCR only works with HTTP transport\n if (auth === 'dcr' && transport === 'stdio') {\n throw new Error('DCR authentication mode requires HTTP transport. DCR is not supported with stdio transport.');\n }\n\n const cliRedirectUri = typeof values['redirect-uri'] === 'string' ? values['redirect-uri'] : undefined;\n const envRedirectUri = env.REDIRECT_URI;\n const redirectUri = cliRedirectUri ?? envRedirectUri;\n if (redirectUri && transport === 'stdio') {\n throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');\n }\n\n const cliHeadless = typeof values.headless === 'boolean' ? values.headless : undefined;\n const envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;\n const headless = cliHeadless ?? envHeadless ?? redirectUri !== undefined; // default for redirectUri is headless (assume server http deployment); otherwise assume local and non-headless\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n let serviceAccountKeyFile: string | undefined;\n if (auth === 'service-account') {\n const cliKeyFile = typeof values['service-account-key-file'] === 'string' ? values['service-account-key-file'] : undefined;\n serviceAccountKeyFile = cliKeyFile ?? env.GOOGLE_SERVICE_ACCOUNT_KEY_FILE;\n\n if (!serviceAccountKeyFile) {\n throw new Error('GOOGLE_SERVICE_ACCOUNT_KEY_FILE environment variable is required when using service account authentication. ' + 'Example: export GOOGLE_SERVICE_ACCOUNT_KEY_FILE=./service-account.json');\n }\n\n // Resolve relative paths now since cwd can change during execution\n serviceAccountKeyFile = resolve(serviceAccountKeyFile);\n }\n\n return {\n clientId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\n ...(serviceAccountKeyFile && { serviceAccountKeyFile }),\n };\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): OAuthConfig {\n return parseConfig(process.argv, process.env);\n}\n\n/**\n * Parse DCR configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --dcr-mode: DCR mode ('self-hosted' | 'external')\n * - Default: 'self-hosted' (if flag is omitted)\n * - --dcr-verify-url: External verification endpoint URL (required for external mode)\n * - --dcr-store-uri: DCR client storage URI (required for self-hosted mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - DCR_MODE: DCR mode (same format as --dcr-mode flag)\n * - DCR_VERIFY_URL: External verification URL (same as --dcr-verify-url flag)\n * - DCR_STORE_URI: DCR storage URI (same as --dcr-store-uri flag)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param scope - OAuth scopes to request (space-separated)\n * @returns Parsed DCR configuration\n * @throws Error if required environment variables are missing or validation fails\n *\n * @example Self-hosted mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=self-hosted', '--dcr-store-uri=file:///path/to/store.json'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n *\n * @example External mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=external', '--dcr-verify-url=https://auth0.example.com/verify'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n */\nexport function parseDcrConfig(args: string[], env: Record<string, string | undefined>, scope: string): DcrConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for DCR configuration`);\n }\n return value;\n }\n\n const { values } = parseArgs({\n args,\n options: {\n 'dcr-mode': { type: 'string' },\n 'dcr-verify-url': { type: 'string' },\n 'dcr-store-uri': { type: 'string' },\n },\n strict: false,\n allowPositionals: true,\n });\n\n const cliMode = typeof values['dcr-mode'] === 'string' ? values['dcr-mode'] : undefined;\n const envMode = env.DCR_MODE;\n const mode = cliMode || envMode || 'self-hosted';\n\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n const cliVerifyUrl = typeof values['dcr-verify-url'] === 'string' ? values['dcr-verify-url'] : undefined;\n const envVerifyUrl = env.DCR_VERIFY_URL;\n const verifyUrl = cliVerifyUrl || envVerifyUrl;\n\n const cliStoreUri = typeof values['dcr-store-uri'] === 'string' ? values['dcr-store-uri'] : undefined;\n const envStoreUri = env.DCR_STORE_URI;\n const storeUri = cliStoreUri || envStoreUri;\n\n if (mode === 'external' && !verifyUrl) {\n throw new Error('DCR external mode requires --dcr-verify-url or DCR_VERIFY_URL environment variable');\n }\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n scope,\n };\n}\n"],"names":["createConfig","parseConfig","parseDcrConfig","parseAuthMode","value","Error","auth","args","env","transport","cliHeadless","requiredEnv","key","values","parseArgs","options","type","headless","strict","allowPositionals","authArg","undefined","envAuthMode","AUTH_MODE","mode","parsed","cliRedirectUri","envRedirectUri","REDIRECT_URI","redirectUri","envHeadless","HEADLESS","clientId","clientSecret","GOOGLE_CLIENT_SECRET","serviceAccountKeyFile","cliKeyFile","GOOGLE_SERVICE_ACCOUNT_KEY_FILE","resolve","process","argv","scope","cliMode","envMode","DCR_MODE","cliVerifyUrl","envVerifyUrl","DCR_VERIFY_URL","verifyUrl","cliStoreUri","envStoreUri","DCR_STORE_URI","storeUri"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/setup/config.ts"],"sourcesContent":["/**\n * Google OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Google OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { resolve } from 'path';\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for direct imports from config.ts\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'service-account' | 'dcr';\n\n/**\n * Parse auth mode string into auth mode.\n *\n * @param value - Auth mode string ('loopback-oauth', 'service-account', or 'dcr')\n * @returns Parsed auth mode\n * @throws Error if value is invalid\n *\n * @example Valid formats\n * ```typescript\n * parseAuthMode('loopback-oauth') // { auth: 'loopback-oauth' }\n * parseAuthMode('service-account') // { auth: 'service-account' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n if (value !== 'loopback-oauth' && value !== 'service-account' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, service-account, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * @typedef {('stdio' | 'http')} TransportType\n * @property {'stdio'} stdio - Standard input/output transport for CLI applications\n * @property {'http'} http - HTTP transport for web-based applications\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Google OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: Auth mode ('loopback-oauth' | 'service-account' | 'dcr')\n * - Default: 'loopback-oauth' (if flag is omitted)\n * - --headless: Disable browser opening for OAuth flow (default: false, true in test env)\n * - --redirect-uri: Override OAuth redirect URI (default: ephemeral loopback)\n * - --service-account-key-file: Service account key file path (required for service-account mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - AUTH_MODE: Auth mode (same format as --auth flag)\n * - HEADLESS: Headless mode flag ('true' to enable)\n * - REDIRECT_URI: OAuth redirect URI (overridden by --redirect-uri CLI flag)\n * - GOOGLE_SERVICE_ACCOUNT_KEY_FILE: Service account key file (for service-account mode)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param transport - Optional transport type. If 'stdio' and auth mode is 'dcr', throws an error.\n * See {@link TransportType} for valid values.\n * @returns Parsed Google OAuth configuration\n * @throws Error if required environment variables are missing, values are invalid, or DCR is used with stdio transport\n *\n * @example Default mode (no flags)\n * ```typescript\n * const config = parseConfig(process.argv, process.env);\n * // { auth: 'loopback-oauth' }\n * ```\n *\n * @example Override auth mode\n * ```typescript\n * parseConfig(['--auth=loopback-oauth'], process.env);\n * parseConfig(['--auth=service-account'], process.env);\n * parseConfig(['--auth=dcr'], process.env);\n * ```\n *\n * @example With transport validation\n * ```typescript\n * parseConfig(['--auth=dcr'], process.env, 'http'); // OK\n * parseConfig(['--auth=dcr'], process.env, 'stdio'); // Throws error\n * ```\n *\n * Valid auth modes:\n * - loopback-oauth (default)\n * - service-account\n * - dcr (HTTP transport only)\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>, transport?: TransportType): OAuthConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for Google OAuth`);\n }\n return value;\n }\n\n // Parse CLI arguments\n const { values } = parseArgs({\n args,\n options: {\n auth: { type: 'string' },\n headless: { type: 'boolean' },\n 'redirect-uri': { type: 'string' },\n 'service-account-key-file': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const authArg = typeof values.auth === 'string' ? values.auth : undefined;\n const envAuthMode = env.AUTH_MODE;\n const mode = authArg || envAuthMode;\n\n let auth: AuthMode;\n\n if (mode) {\n const parsed = parseAuthMode(mode);\n auth = parsed.auth;\n } else {\n // DEFAULT: No flags provided, use loopback-oauth\n auth = 'loopback-oauth';\n }\n\n // Validate: DCR only works with HTTP transport\n if (auth === 'dcr' && transport === 'stdio') {\n throw new Error('DCR authentication mode requires HTTP transport. DCR is not supported with stdio transport.');\n }\n\n const cliRedirectUri = typeof values['redirect-uri'] === 'string' ? values['redirect-uri'] : undefined;\n const envRedirectUri = env.REDIRECT_URI;\n const redirectUri = cliRedirectUri ?? envRedirectUri;\n if (redirectUri && transport === 'stdio') {\n throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');\n }\n\n if (typeof values.headless === 'string') throw new Error('Use --headless or --no-headless (do not pass a value)');\n const cliHeadless = values['no-headless'] ? false : values.headless === true ? true : undefined;\n const envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;\n const headless = cliHeadless ?? envHeadless ?? redirectUri !== undefined;\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n let serviceAccountKeyFile: string | undefined;\n if (auth === 'service-account') {\n const cliKeyFile = typeof values['service-account-key-file'] === 'string' ? values['service-account-key-file'] : undefined;\n serviceAccountKeyFile = cliKeyFile ?? env.GOOGLE_SERVICE_ACCOUNT_KEY_FILE;\n\n if (!serviceAccountKeyFile) {\n throw new Error('GOOGLE_SERVICE_ACCOUNT_KEY_FILE environment variable is required when using service account authentication. ' + 'Example: export GOOGLE_SERVICE_ACCOUNT_KEY_FILE=./service-account.json');\n }\n\n // Resolve relative paths now since cwd can change during execution\n serviceAccountKeyFile = resolve(serviceAccountKeyFile);\n }\n\n return {\n clientId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\n ...(serviceAccountKeyFile && { serviceAccountKeyFile }),\n };\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): OAuthConfig {\n return parseConfig(process.argv, process.env);\n}\n\n/**\n * Parse DCR configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --dcr-mode: DCR mode ('self-hosted' | 'external')\n * - Default: 'self-hosted' (if flag is omitted)\n * - --dcr-verify-url: External verification endpoint URL (required for external mode)\n * - --dcr-store-uri: DCR client storage URI (required for self-hosted mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - DCR_MODE: DCR mode (same format as --dcr-mode flag)\n * - DCR_VERIFY_URL: External verification URL (same as --dcr-verify-url flag)\n * - DCR_STORE_URI: DCR storage URI (same as --dcr-store-uri flag)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param scope - OAuth scopes to request (space-separated)\n * @returns Parsed DCR configuration\n * @throws Error if required environment variables are missing or validation fails\n *\n * @example Self-hosted mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=self-hosted', '--dcr-store-uri=file:///path/to/store.json'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n *\n * @example External mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=external', '--dcr-verify-url=https://auth0.example.com/verify'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n */\nexport function parseDcrConfig(args: string[], env: Record<string, string | undefined>, scope: string): DcrConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for DCR configuration`);\n }\n return value;\n }\n\n const { values } = parseArgs({\n args,\n options: {\n 'dcr-mode': { type: 'string' },\n 'dcr-verify-url': { type: 'string' },\n 'dcr-store-uri': { type: 'string' },\n },\n strict: false,\n allowPositionals: true,\n });\n\n const cliMode = typeof values['dcr-mode'] === 'string' ? values['dcr-mode'] : undefined;\n const envMode = env.DCR_MODE;\n const mode = cliMode || envMode || 'self-hosted';\n\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n const cliVerifyUrl = typeof values['dcr-verify-url'] === 'string' ? values['dcr-verify-url'] : undefined;\n const envVerifyUrl = env.DCR_VERIFY_URL;\n const verifyUrl = cliVerifyUrl || envVerifyUrl;\n\n const cliStoreUri = typeof values['dcr-store-uri'] === 'string' ? values['dcr-store-uri'] : undefined;\n const envStoreUri = env.DCR_STORE_URI;\n const storeUri = cliStoreUri || envStoreUri;\n\n if (mode === 'external' && !verifyUrl) {\n throw new Error('DCR external mode requires --dcr-verify-url or DCR_VERIFY_URL environment variable');\n }\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n scope,\n };\n}\n"],"names":["createConfig","parseConfig","parseDcrConfig","parseAuthMode","value","Error","auth","args","env","transport","cliHeadless","requiredEnv","key","values","parseArgs","options","type","headless","strict","allowPositionals","authArg","undefined","envAuthMode","AUTH_MODE","mode","parsed","cliRedirectUri","envRedirectUri","REDIRECT_URI","redirectUri","envHeadless","HEADLESS","clientId","clientSecret","GOOGLE_CLIENT_SECRET","serviceAccountKeyFile","cliKeyFile","GOOGLE_SERVICE_ACCOUNT_KEY_FILE","resolve","process","argv","scope","cliMode","envMode","DCR_MODE","cliVerifyUrl","envVerifyUrl","DCR_VERIFY_URL","verifyUrl","cliStoreUri","envStoreUri","DCR_STORE_URI","storeUri"],"mappings":"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"}
|
|
@@ -28,6 +28,21 @@ import * as dcrUtils from './dcr-utils.js';
|
|
|
28
28
|
*/ export function createDcrRouter(config) {
|
|
29
29
|
const router = express.Router();
|
|
30
30
|
const { store, issuerUrl, baseUrl, scopesSupported, clientConfig } = config;
|
|
31
|
+
router.use('/mcp', (req, res, next)=>{
|
|
32
|
+
const authHeader = req.headers.authorization || req.headers.Authorization;
|
|
33
|
+
const headerValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;
|
|
34
|
+
if (!headerValue || !headerValue.toLowerCase().startsWith('bearer ')) {
|
|
35
|
+
return res.status(401).set('WWW-Authenticate', `Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource"`).json({
|
|
36
|
+
jsonrpc: '2.0',
|
|
37
|
+
error: {
|
|
38
|
+
code: -32600,
|
|
39
|
+
message: 'Missing Authorization header. DCR mode requires bearer token.'
|
|
40
|
+
},
|
|
41
|
+
id: null
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return next();
|
|
45
|
+
});
|
|
31
46
|
router.use(express.json());
|
|
32
47
|
router.use(express.urlencoded({
|
|
33
48
|
extended: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/lib/dcr-router.ts"],"sourcesContent":["/**\n * DCR Router - OAuth 2.0 Authorization Server\n *\n * Implements OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591)\n * and OAuth 2.0 Authorization Server endpoints (RFC 6749, RFC 8414, RFC 9728).\n *\n * Endpoints:\n * - GET /.well-known/oauth-authorization-server (RFC 8414 metadata)\n * - GET /.well-known/oauth-protected-resource (RFC 9728 metadata - root)\n * - GET /.well-known/oauth-protected-resource/mcp (RFC 9728 metadata - sub-path)\n * - POST /oauth/register (RFC 7591 client registration)\n * - GET /oauth/authorize (RFC 6749 authorization endpoint)\n * - POST /oauth/token (RFC 6749 token endpoint)\n * - POST /oauth/revoke (RFC 7009 token revocation)\n * - GET /oauth/verify (token verification for Resource Server)\n */\n\nimport type { ProviderTokens, RFC8414Metadata, RFC9728Metadata } from '@mcp-z/oauth';\nimport { createHash, randomUUID } from 'crypto';\nimport type { Request, Response } from 'express';\nimport express from 'express';\nimport type { Keyv } from 'keyv';\nimport { DcrOAuthProvider } from '../providers/dcr.ts';\nimport type { AccessToken, AuthorizationCode, OAuthClientConfig } from '../types.ts';\nimport * as dcrUtils from './dcr-utils.ts';\n\n/**\n * Configuration for DCR Router (self-hosted mode only)\n */\nexport interface DcrRouterConfig {\n /** Single Keyv store for all DCR data */\n store: Keyv;\n\n /** Authorization Server issuer URL */\n issuerUrl: string;\n\n /** Base URL for OAuth endpoints */\n baseUrl: string;\n\n /** Supported OAuth scopes */\n scopesSupported: string[];\n\n /** OAuth client configuration for upstream provider */\n clientConfig: OAuthClientConfig;\n}\n\n/**\n * Create DCR Router with OAuth 2.0 endpoints (self-hosted mode)\n *\n * For external mode (Auth0/Stitch), don't call this function - no router needed.\n * The server code should check DcrConfig.mode and only call this for 'self-hosted'.\n *\n * @param config - Router configuration\n * @returns Express router with OAuth endpoints\n */\nexport function createDcrRouter(config: DcrRouterConfig): express.Router {\n const router = express.Router();\n const { store, issuerUrl, baseUrl, scopesSupported, clientConfig } = config;\n\n router.use(express.json());\n router.use(express.urlencoded({ extended: true }));\n\n /**\n * OAuth Authorization Server Metadata (RFC 8414)\n * GET /.well-known/oauth-authorization-server\n */\n router.get('/.well-known/oauth-authorization-server', (_req: Request, res: Response) => {\n const metadata: RFC8414Metadata = {\n issuer: issuerUrl,\n authorization_endpoint: `${baseUrl}/oauth/authorize`,\n token_endpoint: `${baseUrl}/oauth/token`,\n registration_endpoint: `${baseUrl}/oauth/register`,\n revocation_endpoint: `${baseUrl}/oauth/revoke`,\n scopes_supported: scopesSupported,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],\n code_challenge_methods_supported: ['S256', 'plain'],\n service_documentation: `${baseUrl}/docs`,\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Root)\n * GET /.well-known/oauth-protected-resource\n */\n router.get('/.well-known/oauth-protected-resource', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: baseUrl,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Sub-path /mcp)\n * GET /.well-known/oauth-protected-resource/mcp\n */\n router.get('/.well-known/oauth-protected-resource/mcp', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * Dynamic Client Registration (RFC 7591)\n * POST /oauth/register\n */\n router.post('/oauth/register', async (req: Request, res: Response) => {\n try {\n const registrationRequest = req.body;\n const client = await dcrUtils.registerClient(store, registrationRequest);\n res.status(201).json(client);\n } catch (error) {\n res.status(400).json({\n error: 'invalid_client_metadata',\n error_description: error instanceof Error ? error.message : 'Invalid registration request',\n });\n }\n });\n\n /**\n * OAuth Authorization Endpoint (RFC 6749 Section 3.1)\n * GET /oauth/authorize\n *\n * Initiates Google OAuth flow, then generates DCR authorization code\n */\n router.get('/oauth/authorize', async (req: Request, res: Response) => {\n const { response_type, client_id, redirect_uri, scope = '', state = '', code_challenge, code_challenge_method } = req.query;\n\n if (response_type !== 'code') {\n return res.status(400).json({\n error: 'unsupported_response_type',\n error_description: 'Only response_type=code is supported',\n });\n }\n\n if (!client_id || typeof client_id !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'client_id is required',\n });\n }\n\n if (!redirect_uri || typeof redirect_uri !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'redirect_uri is required',\n });\n }\n\n const client = await dcrUtils.getClient(store, client_id);\n if (!client) {\n return res.status(400).json({\n error: 'invalid_client',\n error_description: 'Unknown client_id',\n });\n }\n\n const isValidRedirect = await dcrUtils.validateRedirectUri(store, client_id, redirect_uri);\n if (!isValidRedirect) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid redirect_uri',\n });\n }\n\n const googleState = randomUUID();\n const dcrRequestState = {\n client_id,\n redirect_uri,\n scope: typeof scope === 'string' ? scope : '',\n state: typeof state === 'string' ? state : undefined,\n code_challenge: typeof code_challenge === 'string' ? code_challenge : undefined,\n code_challenge_method: typeof code_challenge_method === 'string' ? code_challenge_method : undefined,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await store.set(`dcr:google-state:${googleState}`, dcrRequestState, 600000);\n\n const googleAuthUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');\n googleAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n googleAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n googleAuthUrl.searchParams.set('response_type', 'code');\n googleAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n googleAuthUrl.searchParams.set('state', googleState);\n googleAuthUrl.searchParams.set('access_type', 'offline');\n googleAuthUrl.searchParams.set('prompt', 'consent');\n\n return res.redirect(googleAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles OAuth callback from Google, exchanges authorization code for tokens,\n * and redirects back to client with DCR authorization code.\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: googleCode, state: googleState, error } = req.query;\n\n if (error) {\n return res.status(400).json({\n error: typeof error === 'string' ? error : 'access_denied',\n error_description: 'Google OAuth authorization failed',\n });\n }\n\n if (!googleCode || typeof googleCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing authorization code from Google',\n });\n }\n\n if (!googleState || typeof googleState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing state parameter',\n });\n }\n\n const dcrRequestState = await store.get(`dcr:google-state:${googleState}`);\n if (!dcrRequestState) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid or expired state parameter',\n });\n }\n\n await store.delete(`dcr:google-state:${googleState}`);\n\n if (Date.now() > dcrRequestState.expires_at) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'DCR request state expired',\n });\n }\n\n const tokenUrl = 'https://oauth2.googleapis.com/token';\n // Build token params - only include client_secret for confidential clients\n // Public clients (Desktop apps) should NOT send client_secret at all\n const tokenParamsObj: Record<string, string> = {\n code: googleCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n grant_type: 'authorization_code',\n };\n if (clientConfig.clientSecret) {\n tokenParamsObj.client_secret = clientConfig.clientSecret;\n }\n const tokenParams = new URLSearchParams(tokenParamsObj);\n\n const tokenResponse = await fetch(tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: tokenParams.toString(),\n });\n\n if (!tokenResponse.ok) {\n const errorText = await tokenResponse.text();\n return res.status(400).json({\n error: 'server_error',\n error_description: `Failed to exchange Google authorization code: ${errorText}`,\n });\n }\n\n const tokenData = (await tokenResponse.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope: string;\n };\n\n // Create provider tokens from Google response\n const providerTokens: ProviderTokens = {\n accessToken: tokenData.access_token,\n ...(tokenData.refresh_token && { refreshToken: tokenData.refresh_token }),\n expiresAt: Date.now() + tokenData.expires_in * 1000,\n scope: tokenData.scope,\n };\n\n const dcrCode = randomUUID();\n const authCode: AuthorizationCode = {\n code: dcrCode,\n client_id: dcrRequestState.client_id,\n redirect_uri: dcrRequestState.redirect_uri,\n scope: dcrRequestState.scope,\n ...(dcrRequestState.code_challenge && { code_challenge: dcrRequestState.code_challenge }),\n ...(dcrRequestState.code_challenge_method && { code_challenge_method: dcrRequestState.code_challenge_method }),\n providerTokens,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await dcrUtils.setAuthCode(store, dcrCode, authCode);\n\n const clientRedirectUrl = new URL(dcrRequestState.redirect_uri);\n clientRedirectUrl.searchParams.set('code', dcrCode);\n if (dcrRequestState.state) {\n clientRedirectUrl.searchParams.set('state', dcrRequestState.state);\n }\n\n return res.redirect(clientRedirectUrl.toString());\n });\n\n /**\n * OAuth Token Endpoint (RFC 6749 Section 3.2)\n * POST /oauth/token\n */\n router.post('/oauth/token', async (req: Request, res: Response) => {\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n const authHeader = req.headers.authorization;\n if (authHeader && authHeader.startsWith('Basic ')) {\n const base64Credentials = authHeader.substring(6);\n const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8');\n const [id, secret] = credentials.split(':');\n client_id = id;\n client_secret = secret;\n }\n\n const { grant_type, code, redirect_uri, refresh_token, code_verifier } = req.body;\n\n if (!grant_type) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'grant_type is required',\n });\n }\n\n if (grant_type === 'authorization_code') {\n if (!code || !client_id || !redirect_uri) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code, client_id, and redirect_uri are required',\n });\n }\n\n // Validate client credentials\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const authCode = await dcrUtils.getAuthCode(store, code);\n if (!authCode) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid or expired authorization code',\n });\n }\n\n if (authCode.client_id !== client_id || authCode.redirect_uri !== redirect_uri) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code mismatch',\n });\n }\n\n if (Date.now() > authCode.expires_at) {\n await dcrUtils.deleteAuthCode(store, code);\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code expired',\n });\n }\n\n if (authCode.code_challenge) {\n if (!code_verifier) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code_verifier is required for PKCE',\n });\n }\n\n const method = authCode.code_challenge_method ?? 'plain';\n const computedChallenge = method === 'S256' ? createHash('sha256').update(code_verifier).digest('base64url') : code_verifier;\n\n if (computedChallenge !== authCode.code_challenge) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid code_verifier',\n });\n }\n }\n\n await dcrUtils.deleteAuthCode(store, code);\n\n const accessToken = randomUUID();\n const refreshTokenValue = randomUUID();\n\n const tokenData: AccessToken = {\n access_token: accessToken,\n token_type: 'Bearer',\n expires_in: 3600,\n refresh_token: refreshTokenValue,\n scope: authCode.scope,\n client_id,\n providerTokens: authCode.providerTokens,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, accessToken, tokenData);\n await dcrUtils.setRefreshToken(store, refreshTokenValue, tokenData);\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n return res.json({\n access_token: tokenData.access_token,\n token_type: tokenData.token_type,\n expires_in: tokenData.expires_in,\n refresh_token: tokenData.refresh_token,\n scope: tokenData.scope,\n });\n }\n if (grant_type === 'refresh_token') {\n if (!refresh_token || !client_id) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'refresh_token and client_id are required',\n });\n }\n\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const tokenData = await dcrUtils.getRefreshToken(store, refresh_token);\n if (!tokenData || tokenData.client_id !== client_id) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid refresh token',\n });\n }\n\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Google tokens\n const provider = new DcrOAuthProvider({\n ...clientConfig,\n scope: tokenData.scope,\n verifyEndpoint: `${baseUrl}/oauth/verify`,\n logger: {\n info: console.log,\n error: console.error,\n warn: console.warn,\n debug: () => {},\n },\n });\n\n // Refresh the Google access token\n refreshedProviderTokens = await provider.refreshAccessToken(tokenData.providerTokens.refreshToken);\n } catch (error) {\n // If refresh fails, continue with existing tokens (they may still be valid)\n console.warn('Provider token refresh failed, using existing tokens:', error instanceof Error ? error.message : String(error));\n }\n }\n\n const newAccessToken = randomUUID();\n const newTokenData: AccessToken = {\n ...tokenData,\n access_token: newAccessToken,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, newAccessToken, newTokenData);\n await dcrUtils.setProviderTokens(store, newAccessToken, refreshedProviderTokens);\n\n return res.json({\n access_token: newTokenData.access_token,\n token_type: newTokenData.token_type,\n expires_in: newTokenData.expires_in,\n scope: newTokenData.scope,\n });\n }\n return res.status(400).json({\n error: 'unsupported_grant_type',\n error_description: 'Only authorization_code and refresh_token grants are supported',\n });\n });\n\n /**\n * OAuth Token Revocation (RFC 7009)\n * POST /oauth/revoke\n */\n router.post('/oauth/revoke', async (req: Request, res: Response) => {\n const { token, token_type_hint, client_id, client_secret } = req.body;\n\n if (!token) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'token is required',\n });\n }\n\n if (client_id && client_secret) {\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret);\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n }\n\n if (token_type_hint === 'refresh_token') {\n await dcrUtils.deleteRefreshToken(store, token);\n } else if (token_type_hint === 'access_token') {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n } else {\n // No hint - try both\n await dcrUtils.deleteRefreshToken(store, token);\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n }\n\n return res.status(200).send();\n });\n\n /**\n * Token Verification Endpoint\n * GET /oauth/verify\n *\n * Validates bearer tokens for Resource Server.\n * Returns AuthInfo with provider tokens for stateless DCR pattern.\n */\n router.get('/oauth/verify', async (req: Request, res: Response) => {\n const authHeader = req.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n error: 'invalid_request',\n error_description: 'Missing or invalid Authorization header',\n });\n }\n\n const token = authHeader.substring(7);\n const tokenData = await dcrUtils.getAccessToken(store, token);\n\n if (!tokenData) {\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Unknown or expired access token',\n });\n }\n\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Access token has expired',\n });\n }\n\n const authInfo = {\n token,\n clientId: tokenData.client_id,\n scopes: tokenData.scope ? tokenData.scope.split(' ') : [],\n expiresAt,\n providerTokens: tokenData.providerTokens,\n };\n\n return res.json(authInfo);\n });\n\n /**\n * Debug endpoint to list registered clients (development only)\n */\n router.get('/debug/clients', async (_req: Request, res: Response) => {\n const clients = await dcrUtils.listClients(store);\n return res.json(clients);\n });\n\n return router;\n}\n"],"names":["createHash","randomUUID","express","DcrOAuthProvider","dcrUtils","createDcrRouter","config","router","Router","store","issuerUrl","baseUrl","scopesSupported","clientConfig","use","json","urlencoded","extended","get","_req","res","metadata","issuer","authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","scopes_supported","response_types_supported","grant_types_supported","token_endpoint_auth_methods_supported","code_challenge_methods_supported","service_documentation","resource","authorization_servers","bearer_methods_supported","post","req","registrationRequest","body","client","registerClient","status","error","error_description","Error","message","response_type","client_id","redirect_uri","scope","state","code_challenge","code_challenge_method","query","getClient","isValidRedirect","validateRedirectUri","googleState","dcrRequestState","undefined","created_at","Date","now","expires_at","set","googleAuthUrl","URL","searchParams","clientId","redirect","toString","code","googleCode","delete","tokenUrl","tokenParamsObj","grant_type","clientSecret","client_secret","tokenParams","URLSearchParams","tokenResponse","fetch","method","headers","ok","errorText","text","tokenData","providerTokens","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","dcrCode","authCode","setAuthCode","clientRedirectUrl","authHeader","authorization","startsWith","base64Credentials","substring","credentials","Buffer","from","id","secret","split","code_verifier","isValidClient","validateClient","getAuthCode","deleteAuthCode","computedChallenge","update","digest","refreshTokenValue","token_type","setAccessToken","setRefreshToken","setProviderTokens","getRefreshToken","refreshedProviderTokens","provider","verifyEndpoint","logger","info","console","log","warn","debug","refreshAccessToken","String","newAccessToken","newTokenData","token","token_type_hint","deleteRefreshToken","deleteAccessToken","deleteProviderTokens","send","getAccessToken","authInfo","scopes","clients","listClients"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/lib/dcr-router.ts"],"sourcesContent":["/**\n * DCR Router - OAuth 2.0 Authorization Server\n *\n * Implements OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591)\n * and OAuth 2.0 Authorization Server endpoints (RFC 6749, RFC 8414, RFC 9728).\n *\n * Endpoints:\n * - GET /.well-known/oauth-authorization-server (RFC 8414 metadata)\n * - GET /.well-known/oauth-protected-resource (RFC 9728 metadata - root)\n * - GET /.well-known/oauth-protected-resource/mcp (RFC 9728 metadata - sub-path)\n * - POST /oauth/register (RFC 7591 client registration)\n * - GET /oauth/authorize (RFC 6749 authorization endpoint)\n * - POST /oauth/token (RFC 6749 token endpoint)\n * - POST /oauth/revoke (RFC 7009 token revocation)\n * - GET /oauth/verify (token verification for Resource Server)\n */\n\nimport type { ProviderTokens, RFC8414Metadata, RFC9728Metadata } from '@mcp-z/oauth';\nimport { createHash, randomUUID } from 'crypto';\nimport type { Request, Response } from 'express';\nimport express from 'express';\nimport type { Keyv } from 'keyv';\nimport { DcrOAuthProvider } from '../providers/dcr.ts';\nimport type { AccessToken, AuthorizationCode, OAuthClientConfig } from '../types.ts';\nimport * as dcrUtils from './dcr-utils.ts';\n\n/**\n * Configuration for DCR Router (self-hosted mode only)\n */\nexport interface DcrRouterConfig {\n /** Single Keyv store for all DCR data */\n store: Keyv;\n\n /** Authorization Server issuer URL */\n issuerUrl: string;\n\n /** Base URL for OAuth endpoints */\n baseUrl: string;\n\n /** Supported OAuth scopes */\n scopesSupported: string[];\n\n /** OAuth client configuration for upstream provider */\n clientConfig: OAuthClientConfig;\n}\n\n/**\n * Create DCR Router with OAuth 2.0 endpoints (self-hosted mode)\n *\n * For external mode (Auth0/Stitch), don't call this function - no router needed.\n * The server code should check DcrConfig.mode and only call this for 'self-hosted'.\n *\n * @param config - Router configuration\n * @returns Express router with OAuth endpoints\n */\nexport function createDcrRouter(config: DcrRouterConfig): express.Router {\n const router = express.Router();\n const { store, issuerUrl, baseUrl, scopesSupported, clientConfig } = config;\n\n router.use('/mcp', (req: Request, res: Response, next) => {\n const authHeader = req.headers.authorization || req.headers.Authorization;\n const headerValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;\n\n if (!headerValue || !headerValue.toLowerCase().startsWith('bearer ')) {\n return res\n .status(401)\n .set('WWW-Authenticate', `Bearer resource_metadata=\"${baseUrl}/.well-known/oauth-protected-resource\"`)\n .json({\n jsonrpc: '2.0',\n error: {\n code: -32600,\n message: 'Missing Authorization header. DCR mode requires bearer token.',\n },\n id: null,\n });\n }\n\n return next();\n });\n\n router.use(express.json());\n router.use(express.urlencoded({ extended: true }));\n\n /**\n * OAuth Authorization Server Metadata (RFC 8414)\n * GET /.well-known/oauth-authorization-server\n */\n router.get('/.well-known/oauth-authorization-server', (_req: Request, res: Response) => {\n const metadata: RFC8414Metadata = {\n issuer: issuerUrl,\n authorization_endpoint: `${baseUrl}/oauth/authorize`,\n token_endpoint: `${baseUrl}/oauth/token`,\n registration_endpoint: `${baseUrl}/oauth/register`,\n revocation_endpoint: `${baseUrl}/oauth/revoke`,\n scopes_supported: scopesSupported,\n response_types_supported: ['code'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'],\n code_challenge_methods_supported: ['S256', 'plain'],\n service_documentation: `${baseUrl}/docs`,\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Root)\n * GET /.well-known/oauth-protected-resource\n */\n router.get('/.well-known/oauth-protected-resource', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: baseUrl,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * OAuth Protected Resource Metadata (RFC 9728 - Sub-path /mcp)\n * GET /.well-known/oauth-protected-resource/mcp\n */\n router.get('/.well-known/oauth-protected-resource/mcp', (_req: Request, res: Response) => {\n const metadata: RFC9728Metadata = {\n resource: `${baseUrl}/mcp`,\n authorization_servers: [baseUrl],\n scopes_supported: scopesSupported,\n bearer_methods_supported: ['header'],\n };\n res.json(metadata);\n });\n\n /**\n * Dynamic Client Registration (RFC 7591)\n * POST /oauth/register\n */\n router.post('/oauth/register', async (req: Request, res: Response) => {\n try {\n const registrationRequest = req.body;\n const client = await dcrUtils.registerClient(store, registrationRequest);\n res.status(201).json(client);\n } catch (error) {\n res.status(400).json({\n error: 'invalid_client_metadata',\n error_description: error instanceof Error ? error.message : 'Invalid registration request',\n });\n }\n });\n\n /**\n * OAuth Authorization Endpoint (RFC 6749 Section 3.1)\n * GET /oauth/authorize\n *\n * Initiates Google OAuth flow, then generates DCR authorization code\n */\n router.get('/oauth/authorize', async (req: Request, res: Response) => {\n const { response_type, client_id, redirect_uri, scope = '', state = '', code_challenge, code_challenge_method } = req.query;\n\n if (response_type !== 'code') {\n return res.status(400).json({\n error: 'unsupported_response_type',\n error_description: 'Only response_type=code is supported',\n });\n }\n\n if (!client_id || typeof client_id !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'client_id is required',\n });\n }\n\n if (!redirect_uri || typeof redirect_uri !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'redirect_uri is required',\n });\n }\n\n const client = await dcrUtils.getClient(store, client_id);\n if (!client) {\n return res.status(400).json({\n error: 'invalid_client',\n error_description: 'Unknown client_id',\n });\n }\n\n const isValidRedirect = await dcrUtils.validateRedirectUri(store, client_id, redirect_uri);\n if (!isValidRedirect) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid redirect_uri',\n });\n }\n\n const googleState = randomUUID();\n const dcrRequestState = {\n client_id,\n redirect_uri,\n scope: typeof scope === 'string' ? scope : '',\n state: typeof state === 'string' ? state : undefined,\n code_challenge: typeof code_challenge === 'string' ? code_challenge : undefined,\n code_challenge_method: typeof code_challenge_method === 'string' ? code_challenge_method : undefined,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await store.set(`dcr:google-state:${googleState}`, dcrRequestState, 600000);\n\n const googleAuthUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');\n googleAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n googleAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n googleAuthUrl.searchParams.set('response_type', 'code');\n googleAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n googleAuthUrl.searchParams.set('state', googleState);\n googleAuthUrl.searchParams.set('access_type', 'offline');\n googleAuthUrl.searchParams.set('prompt', 'consent');\n\n return res.redirect(googleAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles OAuth callback from Google, exchanges authorization code for tokens,\n * and redirects back to client with DCR authorization code.\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: googleCode, state: googleState, error } = req.query;\n\n if (error) {\n return res.status(400).json({\n error: typeof error === 'string' ? error : 'access_denied',\n error_description: 'Google OAuth authorization failed',\n });\n }\n\n if (!googleCode || typeof googleCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing authorization code from Google',\n });\n }\n\n if (!googleState || typeof googleState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Missing state parameter',\n });\n }\n\n const dcrRequestState = await store.get(`dcr:google-state:${googleState}`);\n if (!dcrRequestState) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Invalid or expired state parameter',\n });\n }\n\n await store.delete(`dcr:google-state:${googleState}`);\n\n if (Date.now() > dcrRequestState.expires_at) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'DCR request state expired',\n });\n }\n\n const tokenUrl = 'https://oauth2.googleapis.com/token';\n // Build token params - only include client_secret for confidential clients\n // Public clients (Desktop apps) should NOT send client_secret at all\n const tokenParamsObj: Record<string, string> = {\n code: googleCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n grant_type: 'authorization_code',\n };\n if (clientConfig.clientSecret) {\n tokenParamsObj.client_secret = clientConfig.clientSecret;\n }\n const tokenParams = new URLSearchParams(tokenParamsObj);\n\n const tokenResponse = await fetch(tokenUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: tokenParams.toString(),\n });\n\n if (!tokenResponse.ok) {\n const errorText = await tokenResponse.text();\n return res.status(400).json({\n error: 'server_error',\n error_description: `Failed to exchange Google authorization code: ${errorText}`,\n });\n }\n\n const tokenData = (await tokenResponse.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n scope: string;\n };\n\n // Create provider tokens from Google response\n const providerTokens: ProviderTokens = {\n accessToken: tokenData.access_token,\n ...(tokenData.refresh_token && { refreshToken: tokenData.refresh_token }),\n expiresAt: Date.now() + tokenData.expires_in * 1000,\n scope: tokenData.scope,\n };\n\n const dcrCode = randomUUID();\n const authCode: AuthorizationCode = {\n code: dcrCode,\n client_id: dcrRequestState.client_id,\n redirect_uri: dcrRequestState.redirect_uri,\n scope: dcrRequestState.scope,\n ...(dcrRequestState.code_challenge && { code_challenge: dcrRequestState.code_challenge }),\n ...(dcrRequestState.code_challenge_method && { code_challenge_method: dcrRequestState.code_challenge_method }),\n providerTokens,\n created_at: Date.now(),\n expires_at: Date.now() + 600000, // 10 minutes\n };\n\n await dcrUtils.setAuthCode(store, dcrCode, authCode);\n\n const clientRedirectUrl = new URL(dcrRequestState.redirect_uri);\n clientRedirectUrl.searchParams.set('code', dcrCode);\n if (dcrRequestState.state) {\n clientRedirectUrl.searchParams.set('state', dcrRequestState.state);\n }\n\n return res.redirect(clientRedirectUrl.toString());\n });\n\n /**\n * OAuth Token Endpoint (RFC 6749 Section 3.2)\n * POST /oauth/token\n */\n router.post('/oauth/token', async (req: Request, res: Response) => {\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n const authHeader = req.headers.authorization;\n if (authHeader && authHeader.startsWith('Basic ')) {\n const base64Credentials = authHeader.substring(6);\n const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8');\n const [id, secret] = credentials.split(':');\n client_id = id;\n client_secret = secret;\n }\n\n const { grant_type, code, redirect_uri, refresh_token, code_verifier } = req.body;\n\n if (!grant_type) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'grant_type is required',\n });\n }\n\n if (grant_type === 'authorization_code') {\n if (!code || !client_id || !redirect_uri) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code, client_id, and redirect_uri are required',\n });\n }\n\n // Validate client credentials\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const authCode = await dcrUtils.getAuthCode(store, code);\n if (!authCode) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid or expired authorization code',\n });\n }\n\n if (authCode.client_id !== client_id || authCode.redirect_uri !== redirect_uri) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code mismatch',\n });\n }\n\n if (Date.now() > authCode.expires_at) {\n await dcrUtils.deleteAuthCode(store, code);\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Authorization code expired',\n });\n }\n\n if (authCode.code_challenge) {\n if (!code_verifier) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'code_verifier is required for PKCE',\n });\n }\n\n const method = authCode.code_challenge_method ?? 'plain';\n const computedChallenge = method === 'S256' ? createHash('sha256').update(code_verifier).digest('base64url') : code_verifier;\n\n if (computedChallenge !== authCode.code_challenge) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid code_verifier',\n });\n }\n }\n\n await dcrUtils.deleteAuthCode(store, code);\n\n const accessToken = randomUUID();\n const refreshTokenValue = randomUUID();\n\n const tokenData: AccessToken = {\n access_token: accessToken,\n token_type: 'Bearer',\n expires_in: 3600,\n refresh_token: refreshTokenValue,\n scope: authCode.scope,\n client_id,\n providerTokens: authCode.providerTokens,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, accessToken, tokenData);\n await dcrUtils.setRefreshToken(store, refreshTokenValue, tokenData);\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n return res.json({\n access_token: tokenData.access_token,\n token_type: tokenData.token_type,\n expires_in: tokenData.expires_in,\n refresh_token: tokenData.refresh_token,\n scope: tokenData.scope,\n });\n }\n if (grant_type === 'refresh_token') {\n if (!refresh_token || !client_id) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'refresh_token and client_id are required',\n });\n }\n\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret ?? '');\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n\n const tokenData = await dcrUtils.getRefreshToken(store, refresh_token);\n if (!tokenData || tokenData.client_id !== client_id) {\n return res.status(400).json({\n error: 'invalid_grant',\n error_description: 'Invalid refresh token',\n });\n }\n\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Google tokens\n const provider = new DcrOAuthProvider({\n ...clientConfig,\n scope: tokenData.scope,\n verifyEndpoint: `${baseUrl}/oauth/verify`,\n logger: {\n info: console.log,\n error: console.error,\n warn: console.warn,\n debug: () => {},\n },\n });\n\n // Refresh the Google access token\n refreshedProviderTokens = await provider.refreshAccessToken(tokenData.providerTokens.refreshToken);\n } catch (error) {\n // If refresh fails, continue with existing tokens (they may still be valid)\n console.warn('Provider token refresh failed, using existing tokens:', error instanceof Error ? error.message : String(error));\n }\n }\n\n const newAccessToken = randomUUID();\n const newTokenData: AccessToken = {\n ...tokenData,\n access_token: newAccessToken,\n created_at: Date.now(),\n };\n\n await dcrUtils.setAccessToken(store, newAccessToken, newTokenData);\n await dcrUtils.setProviderTokens(store, newAccessToken, refreshedProviderTokens);\n\n return res.json({\n access_token: newTokenData.access_token,\n token_type: newTokenData.token_type,\n expires_in: newTokenData.expires_in,\n scope: newTokenData.scope,\n });\n }\n return res.status(400).json({\n error: 'unsupported_grant_type',\n error_description: 'Only authorization_code and refresh_token grants are supported',\n });\n });\n\n /**\n * OAuth Token Revocation (RFC 7009)\n * POST /oauth/revoke\n */\n router.post('/oauth/revoke', async (req: Request, res: Response) => {\n const { token, token_type_hint, client_id, client_secret } = req.body;\n\n if (!token) {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'token is required',\n });\n }\n\n if (client_id && client_secret) {\n const isValidClient = await dcrUtils.validateClient(store, client_id, client_secret);\n if (!isValidClient) {\n return res.status(401).json({\n error: 'invalid_client',\n error_description: 'Invalid client credentials',\n });\n }\n }\n\n if (token_type_hint === 'refresh_token') {\n await dcrUtils.deleteRefreshToken(store, token);\n } else if (token_type_hint === 'access_token') {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n } else {\n // No hint - try both\n await dcrUtils.deleteRefreshToken(store, token);\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n }\n\n return res.status(200).send();\n });\n\n /**\n * Token Verification Endpoint\n * GET /oauth/verify\n *\n * Validates bearer tokens for Resource Server.\n * Returns AuthInfo with provider tokens for stateless DCR pattern.\n */\n router.get('/oauth/verify', async (req: Request, res: Response) => {\n const authHeader = req.headers.authorization;\n\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return res.status(401).json({\n error: 'invalid_request',\n error_description: 'Missing or invalid Authorization header',\n });\n }\n\n const token = authHeader.substring(7);\n const tokenData = await dcrUtils.getAccessToken(store, token);\n\n if (!tokenData) {\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Unknown or expired access token',\n });\n }\n\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n await dcrUtils.deleteAccessToken(store, token);\n await dcrUtils.deleteProviderTokens(store, token);\n return res.status(401).json({\n error: 'invalid_token',\n error_description: 'Access token has expired',\n });\n }\n\n const authInfo = {\n token,\n clientId: tokenData.client_id,\n scopes: tokenData.scope ? tokenData.scope.split(' ') : [],\n expiresAt,\n providerTokens: tokenData.providerTokens,\n };\n\n return res.json(authInfo);\n });\n\n /**\n * Debug endpoint to list registered clients (development only)\n */\n router.get('/debug/clients', async (_req: Request, res: Response) => {\n const clients = await dcrUtils.listClients(store);\n return res.json(clients);\n });\n\n return router;\n}\n"],"names":["createHash","randomUUID","express","DcrOAuthProvider","dcrUtils","createDcrRouter","config","router","Router","store","issuerUrl","baseUrl","scopesSupported","clientConfig","use","req","res","next","authHeader","headers","authorization","Authorization","headerValue","Array","isArray","toLowerCase","startsWith","status","set","json","jsonrpc","error","code","message","id","urlencoded","extended","get","_req","metadata","issuer","authorization_endpoint","token_endpoint","registration_endpoint","revocation_endpoint","scopes_supported","response_types_supported","grant_types_supported","token_endpoint_auth_methods_supported","code_challenge_methods_supported","service_documentation","resource","authorization_servers","bearer_methods_supported","post","registrationRequest","body","client","registerClient","error_description","Error","response_type","client_id","redirect_uri","scope","state","code_challenge","code_challenge_method","query","getClient","isValidRedirect","validateRedirectUri","googleState","dcrRequestState","undefined","created_at","Date","now","expires_at","googleAuthUrl","URL","searchParams","clientId","redirect","toString","googleCode","delete","tokenUrl","tokenParamsObj","grant_type","clientSecret","client_secret","tokenParams","URLSearchParams","tokenResponse","fetch","method","ok","errorText","text","tokenData","providerTokens","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","dcrCode","authCode","setAuthCode","clientRedirectUrl","base64Credentials","substring","credentials","Buffer","from","secret","split","code_verifier","isValidClient","validateClient","getAuthCode","deleteAuthCode","computedChallenge","update","digest","refreshTokenValue","token_type","setAccessToken","setRefreshToken","setProviderTokens","getRefreshToken","refreshedProviderTokens","provider","verifyEndpoint","logger","info","console","log","warn","debug","refreshAccessToken","String","newAccessToken","newTokenData","token","token_type_hint","deleteRefreshToken","deleteAccessToken","deleteProviderTokens","send","getAccessToken","authInfo","scopes","clients","listClients"],"mappings":"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"}
|
package/dist/esm/setup/config.js
CHANGED
|
@@ -127,9 +127,10 @@ import { parseArgs } from 'util';
|
|
|
127
127
|
if (redirectUri && transport === 'stdio') {
|
|
128
128
|
throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');
|
|
129
129
|
}
|
|
130
|
-
|
|
130
|
+
if (typeof values.headless === 'string') throw new Error('Use --headless or --no-headless (do not pass a value)');
|
|
131
|
+
const cliHeadless = values['no-headless'] ? false : values.headless === true ? true : undefined;
|
|
131
132
|
const envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;
|
|
132
|
-
const headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined;
|
|
133
|
+
const headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined;
|
|
133
134
|
const clientId = requiredEnv('GOOGLE_CLIENT_ID');
|
|
134
135
|
const clientSecret = env.GOOGLE_CLIENT_SECRET;
|
|
135
136
|
let serviceAccountKeyFile;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/setup/config.ts"],"sourcesContent":["/**\n * Google OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Google OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { resolve } from 'path';\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for direct imports from config.ts\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'service-account' | 'dcr';\n\n/**\n * Parse auth mode string into auth mode.\n *\n * @param value - Auth mode string ('loopback-oauth', 'service-account', or 'dcr')\n * @returns Parsed auth mode\n * @throws Error if value is invalid\n *\n * @example Valid formats\n * ```typescript\n * parseAuthMode('loopback-oauth') // { auth: 'loopback-oauth' }\n * parseAuthMode('service-account') // { auth: 'service-account' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n if (value !== 'loopback-oauth' && value !== 'service-account' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, service-account, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * @typedef {('stdio' | 'http')} TransportType\n * @property {'stdio'} stdio - Standard input/output transport for CLI applications\n * @property {'http'} http - HTTP transport for web-based applications\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Google OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: Auth mode ('loopback-oauth' | 'service-account' | 'dcr')\n * - Default: 'loopback-oauth' (if flag is omitted)\n * - --headless: Disable browser opening for OAuth flow (default: false, true in test env)\n * - --redirect-uri: Override OAuth redirect URI (default: ephemeral loopback)\n * - --service-account-key-file: Service account key file path (required for service-account mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - AUTH_MODE: Auth mode (same format as --auth flag)\n * - HEADLESS: Headless mode flag ('true' to enable)\n * - REDIRECT_URI: OAuth redirect URI (overridden by --redirect-uri CLI flag)\n * - GOOGLE_SERVICE_ACCOUNT_KEY_FILE: Service account key file (for service-account mode)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param transport - Optional transport type. If 'stdio' and auth mode is 'dcr', throws an error.\n * See {@link TransportType} for valid values.\n * @returns Parsed Google OAuth configuration\n * @throws Error if required environment variables are missing, values are invalid, or DCR is used with stdio transport\n *\n * @example Default mode (no flags)\n * ```typescript\n * const config = parseConfig(process.argv, process.env);\n * // { auth: 'loopback-oauth' }\n * ```\n *\n * @example Override auth mode\n * ```typescript\n * parseConfig(['--auth=loopback-oauth'], process.env);\n * parseConfig(['--auth=service-account'], process.env);\n * parseConfig(['--auth=dcr'], process.env);\n * ```\n *\n * @example With transport validation\n * ```typescript\n * parseConfig(['--auth=dcr'], process.env, 'http'); // OK\n * parseConfig(['--auth=dcr'], process.env, 'stdio'); // Throws error\n * ```\n *\n * Valid auth modes:\n * - loopback-oauth (default)\n * - service-account\n * - dcr (HTTP transport only)\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>, transport?: TransportType): OAuthConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for Google OAuth`);\n }\n return value;\n }\n\n // Parse CLI arguments\n const { values } = parseArgs({\n args,\n options: {\n auth: { type: 'string' },\n headless: { type: 'boolean' },\n 'redirect-uri': { type: 'string' },\n 'service-account-key-file': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const authArg = typeof values.auth === 'string' ? values.auth : undefined;\n const envAuthMode = env.AUTH_MODE;\n const mode = authArg || envAuthMode;\n\n let auth: AuthMode;\n\n if (mode) {\n const parsed = parseAuthMode(mode);\n auth = parsed.auth;\n } else {\n // DEFAULT: No flags provided, use loopback-oauth\n auth = 'loopback-oauth';\n }\n\n // Validate: DCR only works with HTTP transport\n if (auth === 'dcr' && transport === 'stdio') {\n throw new Error('DCR authentication mode requires HTTP transport. DCR is not supported with stdio transport.');\n }\n\n const cliRedirectUri = typeof values['redirect-uri'] === 'string' ? values['redirect-uri'] : undefined;\n const envRedirectUri = env.REDIRECT_URI;\n const redirectUri = cliRedirectUri ?? envRedirectUri;\n if (redirectUri && transport === 'stdio') {\n throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');\n }\n\n const cliHeadless = typeof values.headless === 'boolean' ? values.headless : undefined;\n const envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;\n const headless = cliHeadless ?? envHeadless ?? redirectUri !== undefined; // default for redirectUri is headless (assume server http deployment); otherwise assume local and non-headless\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n let serviceAccountKeyFile: string | undefined;\n if (auth === 'service-account') {\n const cliKeyFile = typeof values['service-account-key-file'] === 'string' ? values['service-account-key-file'] : undefined;\n serviceAccountKeyFile = cliKeyFile ?? env.GOOGLE_SERVICE_ACCOUNT_KEY_FILE;\n\n if (!serviceAccountKeyFile) {\n throw new Error('GOOGLE_SERVICE_ACCOUNT_KEY_FILE environment variable is required when using service account authentication. ' + 'Example: export GOOGLE_SERVICE_ACCOUNT_KEY_FILE=./service-account.json');\n }\n\n // Resolve relative paths now since cwd can change during execution\n serviceAccountKeyFile = resolve(serviceAccountKeyFile);\n }\n\n return {\n clientId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\n ...(serviceAccountKeyFile && { serviceAccountKeyFile }),\n };\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): OAuthConfig {\n return parseConfig(process.argv, process.env);\n}\n\n/**\n * Parse DCR configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --dcr-mode: DCR mode ('self-hosted' | 'external')\n * - Default: 'self-hosted' (if flag is omitted)\n * - --dcr-verify-url: External verification endpoint URL (required for external mode)\n * - --dcr-store-uri: DCR client storage URI (required for self-hosted mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - DCR_MODE: DCR mode (same format as --dcr-mode flag)\n * - DCR_VERIFY_URL: External verification URL (same as --dcr-verify-url flag)\n * - DCR_STORE_URI: DCR storage URI (same as --dcr-store-uri flag)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param scope - OAuth scopes to request (space-separated)\n * @returns Parsed DCR configuration\n * @throws Error if required environment variables are missing or validation fails\n *\n * @example Self-hosted mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=self-hosted', '--dcr-store-uri=file:///path/to/store.json'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n *\n * @example External mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=external', '--dcr-verify-url=https://auth0.example.com/verify'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n */\nexport function parseDcrConfig(args: string[], env: Record<string, string | undefined>, scope: string): DcrConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for DCR configuration`);\n }\n return value;\n }\n\n const { values } = parseArgs({\n args,\n options: {\n 'dcr-mode': { type: 'string' },\n 'dcr-verify-url': { type: 'string' },\n 'dcr-store-uri': { type: 'string' },\n },\n strict: false,\n allowPositionals: true,\n });\n\n const cliMode = typeof values['dcr-mode'] === 'string' ? values['dcr-mode'] : undefined;\n const envMode = env.DCR_MODE;\n const mode = cliMode || envMode || 'self-hosted';\n\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n const cliVerifyUrl = typeof values['dcr-verify-url'] === 'string' ? values['dcr-verify-url'] : undefined;\n const envVerifyUrl = env.DCR_VERIFY_URL;\n const verifyUrl = cliVerifyUrl || envVerifyUrl;\n\n const cliStoreUri = typeof values['dcr-store-uri'] === 'string' ? values['dcr-store-uri'] : undefined;\n const envStoreUri = env.DCR_STORE_URI;\n const storeUri = cliStoreUri || envStoreUri;\n\n if (mode === 'external' && !verifyUrl) {\n throw new Error('DCR external mode requires --dcr-verify-url or DCR_VERIFY_URL environment variable');\n }\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n scope,\n };\n}\n"],"names":["resolve","parseArgs","parseAuthMode","value","Error","auth","parseConfig","args","env","transport","cliHeadless","requiredEnv","key","values","options","type","headless","strict","allowPositionals","authArg","undefined","envAuthMode","AUTH_MODE","mode","parsed","cliRedirectUri","envRedirectUri","REDIRECT_URI","redirectUri","envHeadless","HEADLESS","clientId","clientSecret","GOOGLE_CLIENT_SECRET","serviceAccountKeyFile","cliKeyFile","GOOGLE_SERVICE_ACCOUNT_KEY_FILE","createConfig","process","argv","parseDcrConfig","scope","cliMode","envMode","DCR_MODE","cliVerifyUrl","envVerifyUrl","DCR_VERIFY_URL","verifyUrl","cliStoreUri","envStoreUri","DCR_STORE_URI","storeUri"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-google/src/setup/config.ts"],"sourcesContent":["/**\n * Google OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Google OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { resolve } from 'path';\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for direct imports from config.ts\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'service-account' | 'dcr';\n\n/**\n * Parse auth mode string into auth mode.\n *\n * @param value - Auth mode string ('loopback-oauth', 'service-account', or 'dcr')\n * @returns Parsed auth mode\n * @throws Error if value is invalid\n *\n * @example Valid formats\n * ```typescript\n * parseAuthMode('loopback-oauth') // { auth: 'loopback-oauth' }\n * parseAuthMode('service-account') // { auth: 'service-account' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n if (value !== 'loopback-oauth' && value !== 'service-account' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, service-account, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * @typedef {('stdio' | 'http')} TransportType\n * @property {'stdio'} stdio - Standard input/output transport for CLI applications\n * @property {'http'} http - HTTP transport for web-based applications\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Google OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: Auth mode ('loopback-oauth' | 'service-account' | 'dcr')\n * - Default: 'loopback-oauth' (if flag is omitted)\n * - --headless: Disable browser opening for OAuth flow (default: false, true in test env)\n * - --redirect-uri: Override OAuth redirect URI (default: ephemeral loopback)\n * - --service-account-key-file: Service account key file path (required for service-account mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - AUTH_MODE: Auth mode (same format as --auth flag)\n * - HEADLESS: Headless mode flag ('true' to enable)\n * - REDIRECT_URI: OAuth redirect URI (overridden by --redirect-uri CLI flag)\n * - GOOGLE_SERVICE_ACCOUNT_KEY_FILE: Service account key file (for service-account mode)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param transport - Optional transport type. If 'stdio' and auth mode is 'dcr', throws an error.\n * See {@link TransportType} for valid values.\n * @returns Parsed Google OAuth configuration\n * @throws Error if required environment variables are missing, values are invalid, or DCR is used with stdio transport\n *\n * @example Default mode (no flags)\n * ```typescript\n * const config = parseConfig(process.argv, process.env);\n * // { auth: 'loopback-oauth' }\n * ```\n *\n * @example Override auth mode\n * ```typescript\n * parseConfig(['--auth=loopback-oauth'], process.env);\n * parseConfig(['--auth=service-account'], process.env);\n * parseConfig(['--auth=dcr'], process.env);\n * ```\n *\n * @example With transport validation\n * ```typescript\n * parseConfig(['--auth=dcr'], process.env, 'http'); // OK\n * parseConfig(['--auth=dcr'], process.env, 'stdio'); // Throws error\n * ```\n *\n * Valid auth modes:\n * - loopback-oauth (default)\n * - service-account\n * - dcr (HTTP transport only)\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>, transport?: TransportType): OAuthConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for Google OAuth`);\n }\n return value;\n }\n\n // Parse CLI arguments\n const { values } = parseArgs({\n args,\n options: {\n auth: { type: 'string' },\n headless: { type: 'boolean' },\n 'redirect-uri': { type: 'string' },\n 'service-account-key-file': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const authArg = typeof values.auth === 'string' ? values.auth : undefined;\n const envAuthMode = env.AUTH_MODE;\n const mode = authArg || envAuthMode;\n\n let auth: AuthMode;\n\n if (mode) {\n const parsed = parseAuthMode(mode);\n auth = parsed.auth;\n } else {\n // DEFAULT: No flags provided, use loopback-oauth\n auth = 'loopback-oauth';\n }\n\n // Validate: DCR only works with HTTP transport\n if (auth === 'dcr' && transport === 'stdio') {\n throw new Error('DCR authentication mode requires HTTP transport. DCR is not supported with stdio transport.');\n }\n\n const cliRedirectUri = typeof values['redirect-uri'] === 'string' ? values['redirect-uri'] : undefined;\n const envRedirectUri = env.REDIRECT_URI;\n const redirectUri = cliRedirectUri ?? envRedirectUri;\n if (redirectUri && transport === 'stdio') {\n throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');\n }\n\n if (typeof values.headless === 'string') throw new Error('Use --headless or --no-headless (do not pass a value)');\n const cliHeadless = values['no-headless'] ? false : values.headless === true ? true : undefined;\n const envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;\n const headless = cliHeadless ?? envHeadless ?? redirectUri !== undefined;\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n let serviceAccountKeyFile: string | undefined;\n if (auth === 'service-account') {\n const cliKeyFile = typeof values['service-account-key-file'] === 'string' ? values['service-account-key-file'] : undefined;\n serviceAccountKeyFile = cliKeyFile ?? env.GOOGLE_SERVICE_ACCOUNT_KEY_FILE;\n\n if (!serviceAccountKeyFile) {\n throw new Error('GOOGLE_SERVICE_ACCOUNT_KEY_FILE environment variable is required when using service account authentication. ' + 'Example: export GOOGLE_SERVICE_ACCOUNT_KEY_FILE=./service-account.json');\n }\n\n // Resolve relative paths now since cwd can change during execution\n serviceAccountKeyFile = resolve(serviceAccountKeyFile);\n }\n\n return {\n clientId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\n ...(serviceAccountKeyFile && { serviceAccountKeyFile }),\n };\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): OAuthConfig {\n return parseConfig(process.argv, process.env);\n}\n\n/**\n * Parse DCR configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --dcr-mode: DCR mode ('self-hosted' | 'external')\n * - Default: 'self-hosted' (if flag is omitted)\n * - --dcr-verify-url: External verification endpoint URL (required for external mode)\n * - --dcr-store-uri: DCR client storage URI (required for self-hosted mode)\n *\n * Required environment variables:\n * - GOOGLE_CLIENT_ID: OAuth 2.0 client ID from Google Cloud Console\n *\n * Optional environment variables:\n * - GOOGLE_CLIENT_SECRET: OAuth 2.0 client secret (optional for public clients)\n * - DCR_MODE: DCR mode (same format as --dcr-mode flag)\n * - DCR_VERIFY_URL: External verification URL (same as --dcr-verify-url flag)\n * - DCR_STORE_URI: DCR storage URI (same as --dcr-store-uri flag)\n *\n * @param args - CLI arguments array (typically process.argv)\n * @param env - Environment variables object (typically process.env)\n * @param scope - OAuth scopes to request (space-separated)\n * @returns Parsed DCR configuration\n * @throws Error if required environment variables are missing or validation fails\n *\n * @example Self-hosted mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=self-hosted', '--dcr-store-uri=file:///path/to/store.json'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n *\n * @example External mode\n * ```typescript\n * const config = parseDcrConfig(\n * ['--dcr-mode=external', '--dcr-verify-url=https://auth0.example.com/verify'],\n * process.env,\n * 'https://www.googleapis.com/auth/drive.readonly'\n * );\n * ```\n */\nexport function parseDcrConfig(args: string[], env: Record<string, string | undefined>, scope: string): DcrConfig {\n function requiredEnv(key: string): string {\n const value = env[key];\n if (!value) {\n throw new Error(`Environment variable ${key} is required for DCR configuration`);\n }\n return value;\n }\n\n const { values } = parseArgs({\n args,\n options: {\n 'dcr-mode': { type: 'string' },\n 'dcr-verify-url': { type: 'string' },\n 'dcr-store-uri': { type: 'string' },\n },\n strict: false,\n allowPositionals: true,\n });\n\n const cliMode = typeof values['dcr-mode'] === 'string' ? values['dcr-mode'] : undefined;\n const envMode = env.DCR_MODE;\n const mode = cliMode || envMode || 'self-hosted';\n\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n const cliVerifyUrl = typeof values['dcr-verify-url'] === 'string' ? values['dcr-verify-url'] : undefined;\n const envVerifyUrl = env.DCR_VERIFY_URL;\n const verifyUrl = cliVerifyUrl || envVerifyUrl;\n\n const cliStoreUri = typeof values['dcr-store-uri'] === 'string' ? values['dcr-store-uri'] : undefined;\n const envStoreUri = env.DCR_STORE_URI;\n const storeUri = cliStoreUri || envStoreUri;\n\n if (mode === 'external' && !verifyUrl) {\n throw new Error('DCR external mode requires --dcr-verify-url or DCR_VERIFY_URL environment variable');\n }\n\n const clientId = requiredEnv('GOOGLE_CLIENT_ID');\n const clientSecret = env.GOOGLE_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n scope,\n };\n}\n"],"names":["resolve","parseArgs","parseAuthMode","value","Error","auth","parseConfig","args","env","transport","cliHeadless","requiredEnv","key","values","options","type","headless","strict","allowPositionals","authArg","undefined","envAuthMode","AUTH_MODE","mode","parsed","cliRedirectUri","envRedirectUri","REDIRECT_URI","redirectUri","envHeadless","HEADLESS","clientId","clientSecret","GOOGLE_CLIENT_SECRET","serviceAccountKeyFile","cliKeyFile","GOOGLE_SERVICE_ACCOUNT_KEY_FILE","createConfig","process","argv","parseDcrConfig","scope","cliMode","envMode","DCR_MODE","cliVerifyUrl","envVerifyUrl","DCR_VERIFY_URL","verifyUrl","cliStoreUri","envStoreUri","DCR_STORE_URI","storeUri"],"mappings":"AAAA;;;;;;CAMC,GAED,SAASA,OAAO,QAAQ,OAAO;AAC/B,SAASC,SAAS,QAAQ,OAAO;AAWjC;;;;;;;;;;;;;CAaC,GACD,SAASC,cAAcC,KAAa;IAGlC,IAAIA,UAAU,oBAAoBA,UAAU,qBAAqBA,UAAU,OAAO;QAChF,MAAM,IAAIC,MAAM,CAAC,uBAAuB,EAAED,MAAM,qDAAqD,CAAC;IACxG;IAEA,OAAO;QACLE,MAAMF;IACR;AACF;AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDC,GACD,OAAO,SAASG,YAAYC,IAAc,EAAEC,GAAuC,EAAEC,SAAyB;QAmD3FC;IAlDjB,SAASC,YAAYC,GAAW;QAC9B,MAAMT,QAAQK,GAAG,CAACI,IAAI;QACtB,IAAI,CAACT,OAAO;YACV,MAAM,IAAIC,MAAM,CAAC,qBAAqB,EAAEQ,IAAI,6BAA6B,CAAC;QAC5E;QACA,OAAOT;IACT;IAEA,sBAAsB;IACtB,MAAM,EAAEU,MAAM,EAAE,GAAGZ,UAAU;QAC3BM;QACAO,SAAS;YACPT,MAAM;gBAAEU,MAAM;YAAS;YACvBC,UAAU;gBAAED,MAAM;YAAU;YAC5B,gBAAgB;gBAAEA,MAAM;YAAS;YACjC,4BAA4B;gBAAEA,MAAM;YAAS;QAC/C;QACAE,QAAQ;QACRC,kBAAkB;IACpB;IAEA,MAAMC,UAAU,OAAON,OAAOR,IAAI,KAAK,WAAWQ,OAAOR,IAAI,GAAGe;IAChE,MAAMC,cAAcb,IAAIc,SAAS;IACjC,MAAMC,OAAOJ,WAAWE;IAExB,IAAIhB;IAEJ,IAAIkB,MAAM;QACR,MAAMC,SAAStB,cAAcqB;QAC7BlB,OAAOmB,OAAOnB,IAAI;IACpB,OAAO;QACL,iDAAiD;QACjDA,OAAO;IACT;IAEA,+CAA+C;IAC/C,IAAIA,SAAS,SAASI,cAAc,SAAS;QAC3C,MAAM,IAAIL,MAAM;IAClB;IAEA,MAAMqB,iBAAiB,OAAOZ,MAAM,CAAC,eAAe,KAAK,WAAWA,MAAM,CAAC,eAAe,GAAGO;IAC7F,MAAMM,iBAAiBlB,IAAImB,YAAY;IACvC,MAAMC,cAAcH,2BAAAA,4BAAAA,iBAAkBC;IACtC,IAAIE,eAAenB,cAAc,SAAS;QACxC,MAAM,IAAIL,MAAM;IAClB;IAEA,IAAI,OAAOS,OAAOG,QAAQ,KAAK,UAAU,MAAM,IAAIZ,MAAM;IACzD,MAAMM,cAAcG,MAAM,CAAC,cAAc,GAAG,QAAQA,OAAOG,QAAQ,KAAK,OAAO,OAAOI;IACtF,MAAMS,cAAcrB,IAAIsB,QAAQ,KAAK,SAAS,OAAOtB,IAAIsB,QAAQ,KAAK,UAAU,QAAQV;IACxF,MAAMJ,YAAWN,OAAAA,wBAAAA,yBAAAA,cAAemB,yBAAfnB,kBAAAA,OAA8BkB,gBAAgBR;IAE/D,MAAMW,WAAWpB,YAAY;IAC7B,MAAMqB,eAAexB,IAAIyB,oBAAoB;IAE7C,IAAIC;IACJ,IAAI7B,SAAS,mBAAmB;QAC9B,MAAM8B,aAAa,OAAOtB,MAAM,CAAC,2BAA2B,KAAK,WAAWA,MAAM,CAAC,2BAA2B,GAAGO;QACjHc,wBAAwBC,uBAAAA,wBAAAA,aAAc3B,IAAI4B,+BAA+B;QAEzE,IAAI,CAACF,uBAAuB;YAC1B,MAAM,IAAI9B,MAAM,iHAAiH;QACnI;QAEA,mEAAmE;QACnE8B,wBAAwBlC,QAAQkC;IAClC;IAEA,OAAO;QACLH;QACA,GAAIC,gBAAgB;YAAEA;QAAa,CAAC;QACpC3B;QACAW;QACA,GAAIY,eAAe;YAAEA;QAAY,CAAC;QAClC,GAAIM,yBAAyB;YAAEA;QAAsB,CAAC;IACxD;AACF;AAEA;;;CAGC,GACD,OAAO,SAASG;IACd,OAAO/B,YAAYgC,QAAQC,IAAI,EAAED,QAAQ9B,GAAG;AAC9C;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCC,GACD,OAAO,SAASgC,eAAejC,IAAc,EAAEC,GAAuC,EAAEiC,KAAa;IACnG,SAAS9B,YAAYC,GAAW;QAC9B,MAAMT,QAAQK,GAAG,CAACI,IAAI;QACtB,IAAI,CAACT,OAAO;YACV,MAAM,IAAIC,MAAM,CAAC,qBAAqB,EAAEQ,IAAI,kCAAkC,CAAC;QACjF;QACA,OAAOT;IACT;IAEA,MAAM,EAAEU,MAAM,EAAE,GAAGZ,UAAU;QAC3BM;QACAO,SAAS;YACP,YAAY;gBAAEC,MAAM;YAAS;YAC7B,kBAAkB;gBAAEA,MAAM;YAAS;YACnC,iBAAiB;gBAAEA,MAAM;YAAS;QACpC;QACAE,QAAQ;QACRC,kBAAkB;IACpB;IAEA,MAAMwB,UAAU,OAAO7B,MAAM,CAAC,WAAW,KAAK,WAAWA,MAAM,CAAC,WAAW,GAAGO;IAC9E,MAAMuB,UAAUnC,IAAIoC,QAAQ;IAC5B,MAAMrB,OAAOmB,WAAWC,WAAW;IAEnC,IAAIpB,SAAS,iBAAiBA,SAAS,YAAY;QACjD,MAAM,IAAInB,MAAM,CAAC,2BAA2B,EAAEmB,KAAK,sCAAsC,CAAC;IAC5F;IAEA,MAAMsB,eAAe,OAAOhC,MAAM,CAAC,iBAAiB,KAAK,WAAWA,MAAM,CAAC,iBAAiB,GAAGO;IAC/F,MAAM0B,eAAetC,IAAIuC,cAAc;IACvC,MAAMC,YAAYH,gBAAgBC;IAElC,MAAMG,cAAc,OAAOpC,MAAM,CAAC,gBAAgB,KAAK,WAAWA,MAAM,CAAC,gBAAgB,GAAGO;IAC5F,MAAM8B,cAAc1C,IAAI2C,aAAa;IACrC,MAAMC,WAAWH,eAAeC;IAEhC,IAAI3B,SAAS,cAAc,CAACyB,WAAW;QACrC,MAAM,IAAI5C,MAAM;IAClB;IAEA,MAAM2B,WAAWpB,YAAY;IAC7B,MAAMqB,eAAexB,IAAIyB,oBAAoB;IAE7C,OAAO;QACLV;QACA,GAAIyB,aAAa;YAAEA;QAAU,CAAC;QAC9B,GAAII,YAAY;YAAEA;QAAS,CAAC;QAC5BrB;QACA,GAAIC,gBAAgB;YAAEA;QAAa,CAAC;QACpCS;IACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-z/oauth-google",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "OAuth 2.0 client for Google APIs with multi-account support, PKCE security, and swappable storage backends",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oauth2",
|
|
@@ -52,29 +52,29 @@
|
|
|
52
52
|
"version": "tsds version"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@mcp-z/oauth": "^1.0.
|
|
56
|
-
"express": "^5.
|
|
57
|
-
"google-auth-library": "^10.
|
|
58
|
-
"jose": "^6.
|
|
55
|
+
"@mcp-z/oauth": "^1.0.1",
|
|
56
|
+
"express": "^5.2.1",
|
|
57
|
+
"google-auth-library": "^10.5.0",
|
|
58
|
+
"jose": "^6.1.3",
|
|
59
59
|
"open": "^11.0.0",
|
|
60
|
-
"zod": "^4.
|
|
60
|
+
"zod": "^4.3.4"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@mcp-z/client": "^1.0.
|
|
64
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
63
|
+
"@mcp-z/client": "^1.0.4",
|
|
64
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
65
65
|
"@types/cors": "^2.8.19",
|
|
66
66
|
"@types/express": "^5.0.6",
|
|
67
67
|
"@types/mocha": "^10.0.10",
|
|
68
|
-
"@types/node": "^25.0.
|
|
69
|
-
"cors": "^2.
|
|
68
|
+
"@types/node": "^25.0.3",
|
|
69
|
+
"cors": "^2.8.5",
|
|
70
70
|
"dotenv": "^17.2.3",
|
|
71
71
|
"get-port": "^7.1.0",
|
|
72
72
|
"googleapis": "^169.0.0",
|
|
73
73
|
"keyv": "^5.5.5",
|
|
74
74
|
"keyv-file": "^5.3.3",
|
|
75
|
-
"node-version-use": "^2.
|
|
76
|
-
"ts-dev-stack": "^1.
|
|
77
|
-
"tsds-config": "^1.0.
|
|
75
|
+
"node-version-use": "^2.4.7",
|
|
76
|
+
"ts-dev-stack": "^1.22.1",
|
|
77
|
+
"tsds-config": "^1.0.4",
|
|
78
78
|
"typescript": "^5.9.3"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|