@mcp-z/oauth-google 1.0.0

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.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/cjs/index.d.cts +16 -0
  4. package/dist/cjs/index.d.ts +16 -0
  5. package/dist/cjs/index.js +112 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/cjs/lib/dcr-router.d.cts +44 -0
  8. package/dist/cjs/lib/dcr-router.d.ts +44 -0
  9. package/dist/cjs/lib/dcr-router.js +1189 -0
  10. package/dist/cjs/lib/dcr-router.js.map +1 -0
  11. package/dist/cjs/lib/dcr-utils.d.cts +160 -0
  12. package/dist/cjs/lib/dcr-utils.d.ts +160 -0
  13. package/dist/cjs/lib/dcr-utils.js +860 -0
  14. package/dist/cjs/lib/dcr-utils.js.map +1 -0
  15. package/dist/cjs/lib/dcr-verify.d.cts +53 -0
  16. package/dist/cjs/lib/dcr-verify.d.ts +53 -0
  17. package/dist/cjs/lib/dcr-verify.js +193 -0
  18. package/dist/cjs/lib/dcr-verify.js.map +1 -0
  19. package/dist/cjs/lib/fetch-with-timeout.d.cts +14 -0
  20. package/dist/cjs/lib/fetch-with-timeout.d.ts +14 -0
  21. package/dist/cjs/lib/fetch-with-timeout.js +257 -0
  22. package/dist/cjs/lib/fetch-with-timeout.js.map +1 -0
  23. package/dist/cjs/lib/token-verifier.d.cts +44 -0
  24. package/dist/cjs/lib/token-verifier.d.ts +44 -0
  25. package/dist/cjs/lib/token-verifier.js +253 -0
  26. package/dist/cjs/lib/token-verifier.js.map +1 -0
  27. package/dist/cjs/package.json +1 -0
  28. package/dist/cjs/providers/dcr.d.cts +107 -0
  29. package/dist/cjs/providers/dcr.d.ts +107 -0
  30. package/dist/cjs/providers/dcr.js +584 -0
  31. package/dist/cjs/providers/dcr.js.map +1 -0
  32. package/dist/cjs/providers/loopback-oauth.d.cts +119 -0
  33. package/dist/cjs/providers/loopback-oauth.d.ts +119 -0
  34. package/dist/cjs/providers/loopback-oauth.js +1334 -0
  35. package/dist/cjs/providers/loopback-oauth.js.map +1 -0
  36. package/dist/cjs/providers/service-account.d.cts +131 -0
  37. package/dist/cjs/providers/service-account.d.ts +131 -0
  38. package/dist/cjs/providers/service-account.js +800 -0
  39. package/dist/cjs/providers/service-account.js.map +1 -0
  40. package/dist/cjs/schemas/index.d.cts +20 -0
  41. package/dist/cjs/schemas/index.d.ts +20 -0
  42. package/dist/cjs/schemas/index.js +37 -0
  43. package/dist/cjs/schemas/index.js.map +1 -0
  44. package/dist/cjs/setup/config.d.cts +112 -0
  45. package/dist/cjs/setup/config.d.ts +112 -0
  46. package/dist/cjs/setup/config.js +236 -0
  47. package/dist/cjs/setup/config.js.map +1 -0
  48. package/dist/cjs/types.d.cts +173 -0
  49. package/dist/cjs/types.d.ts +173 -0
  50. package/dist/cjs/types.js +16 -0
  51. package/dist/cjs/types.js.map +1 -0
  52. package/dist/esm/index.d.ts +16 -0
  53. package/dist/esm/index.js +16 -0
  54. package/dist/esm/index.js.map +1 -0
  55. package/dist/esm/lib/dcr-router.d.ts +44 -0
  56. package/dist/esm/lib/dcr-router.js +515 -0
  57. package/dist/esm/lib/dcr-router.js.map +1 -0
  58. package/dist/esm/lib/dcr-utils.d.ts +160 -0
  59. package/dist/esm/lib/dcr-utils.js +270 -0
  60. package/dist/esm/lib/dcr-utils.js.map +1 -0
  61. package/dist/esm/lib/dcr-verify.d.ts +53 -0
  62. package/dist/esm/lib/dcr-verify.js +53 -0
  63. package/dist/esm/lib/dcr-verify.js.map +1 -0
  64. package/dist/esm/lib/fetch-with-timeout.d.ts +14 -0
  65. package/dist/esm/lib/fetch-with-timeout.js +30 -0
  66. package/dist/esm/lib/fetch-with-timeout.js.map +1 -0
  67. package/dist/esm/lib/token-verifier.d.ts +44 -0
  68. package/dist/esm/lib/token-verifier.js +53 -0
  69. package/dist/esm/lib/token-verifier.js.map +1 -0
  70. package/dist/esm/package.json +1 -0
  71. package/dist/esm/providers/dcr.d.ts +107 -0
  72. package/dist/esm/providers/dcr.js +242 -0
  73. package/dist/esm/providers/dcr.js.map +1 -0
  74. package/dist/esm/providers/loopback-oauth.d.ts +119 -0
  75. package/dist/esm/providers/loopback-oauth.js +639 -0
  76. package/dist/esm/providers/loopback-oauth.js.map +1 -0
  77. package/dist/esm/providers/service-account.d.ts +131 -0
  78. package/dist/esm/providers/service-account.js +353 -0
  79. package/dist/esm/providers/service-account.js.map +1 -0
  80. package/dist/esm/schemas/index.d.ts +20 -0
  81. package/dist/esm/schemas/index.js +18 -0
  82. package/dist/esm/schemas/index.js.map +1 -0
  83. package/dist/esm/setup/config.d.ts +112 -0
  84. package/dist/esm/setup/config.js +258 -0
  85. package/dist/esm/setup/config.js.map +1 -0
  86. package/dist/esm/types.d.ts +173 -0
  87. package/dist/esm/types.js +6 -0
  88. package/dist/esm/types.js.map +1 -0
  89. package/package.json +89 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/oauth/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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"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * DCR Storage Utilities
3
+ *
4
+ * Keyv-based storage utilities for Dynamic Client Registration.
5
+ * Follows @mcp-z/oauth pattern: single Keyv store with compound keys.
6
+ *
7
+ * Key Patterns:
8
+ * - dcr:client:{clientId} -> RegisteredClient
9
+ * - dcr:provider:{dcrToken} -> ProviderTokens
10
+ * - dcr:authcode:{code} -> AuthorizationCode
11
+ * - dcr:access:{token} -> AccessToken
12
+ * - dcr:refresh:{token} -> AccessToken
13
+ */
14
+ import type { DcrClientInformation, DcrClientMetadata, ProviderTokens } from '@mcp-z/oauth';
15
+ import type { Keyv } from 'keyv';
16
+ import type { AccessToken, AuthorizationCode, RegisteredClient } from '../types.js';
17
+ /**
18
+ * Register a new OAuth client (RFC 7591 Section 3.1)
19
+ *
20
+ * @param store - Keyv store for all DCR data
21
+ * @param metadata - Client registration metadata
22
+ * @returns Registered client with credentials
23
+ * @throws Error if validation fails
24
+ */
25
+ export declare function registerClient(store: Keyv, metadata: DcrClientMetadata): Promise<DcrClientInformation>;
26
+ /**
27
+ * Get a registered client by ID
28
+ *
29
+ * @param store - Keyv store for all DCR data
30
+ * @param clientId - Client identifier
31
+ * @returns Registered client or undefined if not found
32
+ */
33
+ export declare function getClient(store: Keyv, clientId: string): Promise<RegisteredClient | undefined>;
34
+ /**
35
+ * Validate client credentials
36
+ *
37
+ * @param store - Keyv store for all DCR data
38
+ * @param clientId - Client identifier
39
+ * @param clientSecret - Client secret
40
+ * @returns True if credentials are valid
41
+ */
42
+ export declare function validateClient(store: Keyv, clientId: string, clientSecret: string): Promise<boolean>;
43
+ /**
44
+ * Validate redirect URI for a client
45
+ *
46
+ * @param store - Keyv store for all DCR data
47
+ * @param clientId - Client identifier
48
+ * @param redirectUri - Redirect URI to validate
49
+ * @returns True if redirect URI is registered
50
+ */
51
+ export declare function validateRedirectUri(store: Keyv, clientId: string, redirectUri: string): Promise<boolean>;
52
+ /**
53
+ * List all registered clients (for debugging)
54
+ *
55
+ * Note: This method uses Keyv's iterator which may not be available on all storage adapters.
56
+ * For production use, consider maintaining a separate index of client IDs.
57
+ *
58
+ * @param store - Keyv store for all DCR data
59
+ * @returns Array of all registered clients
60
+ */
61
+ export declare function listClients(store: Keyv): Promise<RegisteredClient[]>;
62
+ /**
63
+ * Delete a registered client
64
+ *
65
+ * @param store - Keyv store for all DCR data
66
+ * @param clientId - Client identifier
67
+ */
68
+ export declare function deleteClient(store: Keyv, clientId: string): Promise<void>;
69
+ /**
70
+ * Store provider tokens for a DCR access token
71
+ *
72
+ * @param store - Keyv store for all DCR data
73
+ * @param dcrToken - DCR-issued access token (used as key)
74
+ * @param tokens - Google provider tokens (access, refresh, expiry)
75
+ */
76
+ export declare function setProviderTokens(store: Keyv, dcrToken: string, tokens: ProviderTokens): Promise<void>;
77
+ /**
78
+ * Retrieve provider tokens for a DCR access token
79
+ *
80
+ * @param store - Keyv store for all DCR data
81
+ * @param dcrToken - DCR-issued access token
82
+ * @returns Provider tokens or undefined if not found
83
+ */
84
+ export declare function getProviderTokens(store: Keyv, dcrToken: string): Promise<ProviderTokens | undefined>;
85
+ /**
86
+ * Delete provider tokens for a DCR access token
87
+ *
88
+ * @param store - Keyv store for all DCR data
89
+ * @param dcrToken - DCR-issued access token
90
+ */
91
+ export declare function deleteProviderTokens(store: Keyv, dcrToken: string): Promise<void>;
92
+ /**
93
+ * Store an authorization code
94
+ *
95
+ * @param store - Keyv store for all DCR data
96
+ * @param code - Authorization code
97
+ * @param authCode - Authorization code data
98
+ */
99
+ export declare function setAuthCode(store: Keyv, code: string, authCode: AuthorizationCode): Promise<void>;
100
+ /**
101
+ * Get an authorization code
102
+ *
103
+ * @param store - Keyv store for all DCR data
104
+ * @param code - Authorization code
105
+ * @returns Authorization code data or undefined if not found
106
+ */
107
+ export declare function getAuthCode(store: Keyv, code: string): Promise<AuthorizationCode | undefined>;
108
+ /**
109
+ * Delete an authorization code
110
+ *
111
+ * @param store - Keyv store for all DCR data
112
+ * @param code - Authorization code
113
+ */
114
+ export declare function deleteAuthCode(store: Keyv, code: string): Promise<void>;
115
+ /**
116
+ * Store an access token
117
+ *
118
+ * @param store - Keyv store for all DCR data
119
+ * @param token - Access token
120
+ * @param tokenData - Access token data
121
+ */
122
+ export declare function setAccessToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void>;
123
+ /**
124
+ * Get an access token
125
+ *
126
+ * @param store - Keyv store for all DCR data
127
+ * @param token - Access token
128
+ * @returns Access token data or undefined if not found
129
+ */
130
+ export declare function getAccessToken(store: Keyv, token: string): Promise<AccessToken | undefined>;
131
+ /**
132
+ * Delete an access token
133
+ *
134
+ * @param store - Keyv store for all DCR data
135
+ * @param token - Access token
136
+ */
137
+ export declare function deleteAccessToken(store: Keyv, token: string): Promise<void>;
138
+ /**
139
+ * Store a refresh token
140
+ *
141
+ * @param store - Keyv store for all DCR data
142
+ * @param token - Refresh token
143
+ * @param tokenData - Access token data (contains refresh token context)
144
+ */
145
+ export declare function setRefreshToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void>;
146
+ /**
147
+ * Get a refresh token
148
+ *
149
+ * @param store - Keyv store for all DCR data
150
+ * @param token - Refresh token
151
+ * @returns Access token data or undefined if not found
152
+ */
153
+ export declare function getRefreshToken(store: Keyv, token: string): Promise<AccessToken | undefined>;
154
+ /**
155
+ * Delete a refresh token
156
+ *
157
+ * @param store - Keyv store for all DCR data
158
+ * @param token - Refresh token
159
+ */
160
+ export declare function deleteRefreshToken(store: Keyv, token: string): Promise<void>;
@@ -0,0 +1,160 @@
1
+ /**
2
+ * DCR Storage Utilities
3
+ *
4
+ * Keyv-based storage utilities for Dynamic Client Registration.
5
+ * Follows @mcp-z/oauth pattern: single Keyv store with compound keys.
6
+ *
7
+ * Key Patterns:
8
+ * - dcr:client:{clientId} -> RegisteredClient
9
+ * - dcr:provider:{dcrToken} -> ProviderTokens
10
+ * - dcr:authcode:{code} -> AuthorizationCode
11
+ * - dcr:access:{token} -> AccessToken
12
+ * - dcr:refresh:{token} -> AccessToken
13
+ */
14
+ import type { DcrClientInformation, DcrClientMetadata, ProviderTokens } from '@mcp-z/oauth';
15
+ import type { Keyv } from 'keyv';
16
+ import type { AccessToken, AuthorizationCode, RegisteredClient } from '../types.js';
17
+ /**
18
+ * Register a new OAuth client (RFC 7591 Section 3.1)
19
+ *
20
+ * @param store - Keyv store for all DCR data
21
+ * @param metadata - Client registration metadata
22
+ * @returns Registered client with credentials
23
+ * @throws Error if validation fails
24
+ */
25
+ export declare function registerClient(store: Keyv, metadata: DcrClientMetadata): Promise<DcrClientInformation>;
26
+ /**
27
+ * Get a registered client by ID
28
+ *
29
+ * @param store - Keyv store for all DCR data
30
+ * @param clientId - Client identifier
31
+ * @returns Registered client or undefined if not found
32
+ */
33
+ export declare function getClient(store: Keyv, clientId: string): Promise<RegisteredClient | undefined>;
34
+ /**
35
+ * Validate client credentials
36
+ *
37
+ * @param store - Keyv store for all DCR data
38
+ * @param clientId - Client identifier
39
+ * @param clientSecret - Client secret
40
+ * @returns True if credentials are valid
41
+ */
42
+ export declare function validateClient(store: Keyv, clientId: string, clientSecret: string): Promise<boolean>;
43
+ /**
44
+ * Validate redirect URI for a client
45
+ *
46
+ * @param store - Keyv store for all DCR data
47
+ * @param clientId - Client identifier
48
+ * @param redirectUri - Redirect URI to validate
49
+ * @returns True if redirect URI is registered
50
+ */
51
+ export declare function validateRedirectUri(store: Keyv, clientId: string, redirectUri: string): Promise<boolean>;
52
+ /**
53
+ * List all registered clients (for debugging)
54
+ *
55
+ * Note: This method uses Keyv's iterator which may not be available on all storage adapters.
56
+ * For production use, consider maintaining a separate index of client IDs.
57
+ *
58
+ * @param store - Keyv store for all DCR data
59
+ * @returns Array of all registered clients
60
+ */
61
+ export declare function listClients(store: Keyv): Promise<RegisteredClient[]>;
62
+ /**
63
+ * Delete a registered client
64
+ *
65
+ * @param store - Keyv store for all DCR data
66
+ * @param clientId - Client identifier
67
+ */
68
+ export declare function deleteClient(store: Keyv, clientId: string): Promise<void>;
69
+ /**
70
+ * Store provider tokens for a DCR access token
71
+ *
72
+ * @param store - Keyv store for all DCR data
73
+ * @param dcrToken - DCR-issued access token (used as key)
74
+ * @param tokens - Google provider tokens (access, refresh, expiry)
75
+ */
76
+ export declare function setProviderTokens(store: Keyv, dcrToken: string, tokens: ProviderTokens): Promise<void>;
77
+ /**
78
+ * Retrieve provider tokens for a DCR access token
79
+ *
80
+ * @param store - Keyv store for all DCR data
81
+ * @param dcrToken - DCR-issued access token
82
+ * @returns Provider tokens or undefined if not found
83
+ */
84
+ export declare function getProviderTokens(store: Keyv, dcrToken: string): Promise<ProviderTokens | undefined>;
85
+ /**
86
+ * Delete provider tokens for a DCR access token
87
+ *
88
+ * @param store - Keyv store for all DCR data
89
+ * @param dcrToken - DCR-issued access token
90
+ */
91
+ export declare function deleteProviderTokens(store: Keyv, dcrToken: string): Promise<void>;
92
+ /**
93
+ * Store an authorization code
94
+ *
95
+ * @param store - Keyv store for all DCR data
96
+ * @param code - Authorization code
97
+ * @param authCode - Authorization code data
98
+ */
99
+ export declare function setAuthCode(store: Keyv, code: string, authCode: AuthorizationCode): Promise<void>;
100
+ /**
101
+ * Get an authorization code
102
+ *
103
+ * @param store - Keyv store for all DCR data
104
+ * @param code - Authorization code
105
+ * @returns Authorization code data or undefined if not found
106
+ */
107
+ export declare function getAuthCode(store: Keyv, code: string): Promise<AuthorizationCode | undefined>;
108
+ /**
109
+ * Delete an authorization code
110
+ *
111
+ * @param store - Keyv store for all DCR data
112
+ * @param code - Authorization code
113
+ */
114
+ export declare function deleteAuthCode(store: Keyv, code: string): Promise<void>;
115
+ /**
116
+ * Store an access token
117
+ *
118
+ * @param store - Keyv store for all DCR data
119
+ * @param token - Access token
120
+ * @param tokenData - Access token data
121
+ */
122
+ export declare function setAccessToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void>;
123
+ /**
124
+ * Get an access token
125
+ *
126
+ * @param store - Keyv store for all DCR data
127
+ * @param token - Access token
128
+ * @returns Access token data or undefined if not found
129
+ */
130
+ export declare function getAccessToken(store: Keyv, token: string): Promise<AccessToken | undefined>;
131
+ /**
132
+ * Delete an access token
133
+ *
134
+ * @param store - Keyv store for all DCR data
135
+ * @param token - Access token
136
+ */
137
+ export declare function deleteAccessToken(store: Keyv, token: string): Promise<void>;
138
+ /**
139
+ * Store a refresh token
140
+ *
141
+ * @param store - Keyv store for all DCR data
142
+ * @param token - Refresh token
143
+ * @param tokenData - Access token data (contains refresh token context)
144
+ */
145
+ export declare function setRefreshToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void>;
146
+ /**
147
+ * Get a refresh token
148
+ *
149
+ * @param store - Keyv store for all DCR data
150
+ * @param token - Refresh token
151
+ * @returns Access token data or undefined if not found
152
+ */
153
+ export declare function getRefreshToken(store: Keyv, token: string): Promise<AccessToken | undefined>;
154
+ /**
155
+ * Delete a refresh token
156
+ *
157
+ * @param store - Keyv store for all DCR data
158
+ * @param token - Refresh token
159
+ */
160
+ export declare function deleteRefreshToken(store: Keyv, token: string): Promise<void>;