@mcp-z/oauth-microsoft 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.
@@ -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
  // Apply required middleware for OAuth 2.0 endpoints (RFC 6749)
313
328
  router.use(_express.default.json()); // For /oauth/register (application/json)
314
329
  router.use(_express.default.urlencoded({
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/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 // Apply required middleware for OAuth 2.0 endpoints (RFC 6749)\n router.use(express.json()); // For /oauth/register (application/json)\n router.use(express.urlencoded({ extended: true })); // For /oauth/token (application/x-www-form-urlencoded)\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\n // Register the client\n const client = await dcrUtils.registerClient(store, registrationRequest);\n\n // Return client information (RFC 7591 Section 3.2.1)\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 Microsoft 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 // Validate required parameters\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 // Validate client\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 // Validate redirect_uri\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 // Store DCR request state for Microsoft OAuth callback\n const msState = 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:ms-state:${msState}`, dcrRequestState, 600000); // 10 min TTL\n\n // Build Microsoft authorization URL\n const msAuthUrl = new URL(`https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/authorize`);\n msAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n msAuthUrl.searchParams.set('response_type', 'code');\n msAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n msAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n msAuthUrl.searchParams.set('state', msState);\n msAuthUrl.searchParams.set('response_mode', 'query');\n\n // Redirect user to Microsoft for authorization\n return res.redirect(msAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles callback from Microsoft after user authorization\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: msCode, state: msState, error, error_description } = req.query;\n\n // Handle Microsoft OAuth errors\n if (error) {\n return res.status(400).json({\n error,\n error_description: error_description || 'Microsoft OAuth authorization failed',\n });\n }\n\n if (!msCode || typeof msCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Authorization code is required',\n });\n }\n\n if (!msState || typeof msState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'State parameter is required',\n });\n }\n\n // Retrieve original DCR request state\n const dcrRequestState = await store.get(`dcr:ms-state:${msState}`);\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 // Delete state (one-time use)\n await store.delete(`dcr:ms-state:${msState}`);\n\n // Exchange Microsoft authorization code for tokens\n try {\n const tokenUrl = `https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/token`;\n const tokenParams = new URLSearchParams({\n grant_type: 'authorization_code',\n code: msCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n scope: dcrRequestState.scope,\n });\n\n // Add client_secret if available (confidential client)\n if (clientConfig.clientSecret) {\n tokenParams.set('client_secret', clientConfig.clientSecret);\n }\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 errorData = (await tokenResponse.json()) as { error?: string; error_description?: string };\n throw new Error(`Microsoft token exchange failed: ${errorData.error_description || errorData.error}`);\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 Microsoft 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 // Generate DCR authorization code with real provider tokens\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 // Redirect back to MCP client with DCR authorization code\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 } catch (error) {\n return res.status(500).json({\n error: 'server_error',\n error_description: error instanceof Error ? error.message : 'Failed to exchange authorization code',\n });\n }\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 // Extract client credentials from either body or Basic Auth header\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n // Support client_secret_basic authentication (RFC 6749 Section 2.3.1)\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 // Validate grant_type\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 // Authorization Code Grant\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 // Get authorization code\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 // Validate authorization code\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 // Validate PKCE if used\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 // Validate code_verifier against code_challenge\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 // Delete authorization code (one-time use)\n await dcrUtils.deleteAuthCode(store, code);\n\n // Generate DCR access token\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\n // Store provider tokens indexed by DCR access token\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n // Return token response\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 // Refresh Token Grant\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 // 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 // Get refresh token\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 // Refresh provider tokens if available\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Microsoft tokens\n const provider = new DcrOAuthProvider({\n clientId: clientConfig.clientId,\n ...(clientConfig.clientSecret && { clientSecret: clientConfig.clientSecret }),\n tenantId: clientConfig.tenantId ?? 'common',\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 Microsoft 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 // Generate new DCR access token\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\n // Store refreshed provider tokens indexed by new DCR access token\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 // Validate client if credentials provided\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 // Revoke the token\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 // RFC 7009: Return 200 even if token not found\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 // Extract bearer token from Authorization header\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); // Remove 'Bearer ' prefix\n\n // Validate token exists in access tokens store\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 // Check if token is expired\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n // Remove expired token\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 // Return AuthInfo with provider tokens for stateless DCR\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 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","msState","dcrRequestState","msAuthUrl","query","getClient","validateRedirectUri","randomUUID","undefined","created_at","Date","now","expires_at","set","URL","tenantId","searchParams","clientId","redirect","toString","msCode","tokenUrl","tokenParams","tokenResponse","errorData","tokenData","providerTokens","dcrCode","authCode","clientRedirectUrl","code","delete","URLSearchParams","grant_type","clientSecret","fetch","method","headers","ok","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","setAuthCode","client_secret","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-microsoft/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 // Apply required middleware for OAuth 2.0 endpoints (RFC 6749)\n router.use(express.json()); // For /oauth/register (application/json)\n router.use(express.urlencoded({ extended: true })); // For /oauth/token (application/x-www-form-urlencoded)\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\n // Register the client\n const client = await dcrUtils.registerClient(store, registrationRequest);\n\n // Return client information (RFC 7591 Section 3.2.1)\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 Microsoft 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 // Validate required parameters\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 // Validate client\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 // Validate redirect_uri\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 // Store DCR request state for Microsoft OAuth callback\n const msState = 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:ms-state:${msState}`, dcrRequestState, 600000); // 10 min TTL\n\n // Build Microsoft authorization URL\n const msAuthUrl = new URL(`https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/authorize`);\n msAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n msAuthUrl.searchParams.set('response_type', 'code');\n msAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n msAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n msAuthUrl.searchParams.set('state', msState);\n msAuthUrl.searchParams.set('response_mode', 'query');\n\n // Redirect user to Microsoft for authorization\n return res.redirect(msAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles callback from Microsoft after user authorization\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: msCode, state: msState, error, error_description } = req.query;\n\n // Handle Microsoft OAuth errors\n if (error) {\n return res.status(400).json({\n error,\n error_description: error_description || 'Microsoft OAuth authorization failed',\n });\n }\n\n if (!msCode || typeof msCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Authorization code is required',\n });\n }\n\n if (!msState || typeof msState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'State parameter is required',\n });\n }\n\n // Retrieve original DCR request state\n const dcrRequestState = await store.get(`dcr:ms-state:${msState}`);\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 // Delete state (one-time use)\n await store.delete(`dcr:ms-state:${msState}`);\n\n // Exchange Microsoft authorization code for tokens\n try {\n const tokenUrl = `https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/token`;\n const tokenParams = new URLSearchParams({\n grant_type: 'authorization_code',\n code: msCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n scope: dcrRequestState.scope,\n });\n\n // Add client_secret if available (confidential client)\n if (clientConfig.clientSecret) {\n tokenParams.set('client_secret', clientConfig.clientSecret);\n }\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 errorData = (await tokenResponse.json()) as { error?: string; error_description?: string };\n throw new Error(`Microsoft token exchange failed: ${errorData.error_description || errorData.error}`);\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 Microsoft 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 // Generate DCR authorization code with real provider tokens\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 // Redirect back to MCP client with DCR authorization code\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 } catch (error) {\n return res.status(500).json({\n error: 'server_error',\n error_description: error instanceof Error ? error.message : 'Failed to exchange authorization code',\n });\n }\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 // Extract client credentials from either body or Basic Auth header\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n // Support client_secret_basic authentication (RFC 6749 Section 2.3.1)\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 // Validate grant_type\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 // Authorization Code Grant\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 // Get authorization code\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 // Validate authorization code\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 // Validate PKCE if used\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 // Validate code_verifier against code_challenge\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 // Delete authorization code (one-time use)\n await dcrUtils.deleteAuthCode(store, code);\n\n // Generate DCR access token\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\n // Store provider tokens indexed by DCR access token\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n // Return token response\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 // Refresh Token Grant\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 // 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 // Get refresh token\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 // Refresh provider tokens if available\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Microsoft tokens\n const provider = new DcrOAuthProvider({\n clientId: clientConfig.clientId,\n ...(clientConfig.clientSecret && { clientSecret: clientConfig.clientSecret }),\n tenantId: clientConfig.tenantId ?? 'common',\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 Microsoft 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 // Generate new DCR access token\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\n // Store refreshed provider tokens indexed by new DCR access token\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 // Validate client if credentials provided\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 // Revoke the token\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 // RFC 7009: Return 200 even if token not found\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 // Extract bearer token from Authorization header\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); // Remove 'Bearer ' prefix\n\n // Validate token exists in access tokens store\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 // Check if token is expired\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n // Remove expired token\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 // Return AuthInfo with provider tokens for stateless DCR\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 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","msState","dcrRequestState","msAuthUrl","query","getClient","validateRedirectUri","randomUUID","undefined","created_at","Date","now","expires_at","URL","tenantId","searchParams","clientId","redirect","toString","msCode","tokenUrl","tokenParams","tokenResponse","errorData","tokenData","providerTokens","dcrCode","authCode","clientRedirectUrl","delete","URLSearchParams","grant_type","clientSecret","fetch","method","ok","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","setAuthCode","client_secret","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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"}
@@ -153,9 +153,10 @@ function parseConfig(args, env, transport) {
153
153
  throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');
154
154
  }
155
155
  // Parse headless mode
156
- var cliHeadless = typeof values.headless === 'boolean' ? values.headless : undefined;
156
+ if (typeof values.headless === 'string') throw new Error('Use --headless or --no-headless (do not pass a value)');
157
+ var cliHeadless = values['no-headless'] ? false : values.headless === true ? true : undefined;
157
158
  var envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;
158
- var headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined; // default for redirectUri is headless (assume server http deployment); otherwise assume local and non-headless
159
+ var headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined;
159
160
  // Parse tenant-id (CLI overrides environment)
160
161
  var cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;
161
162
  var tenantId = cliTenantId !== null && cliTenantId !== void 0 ? cliTenantId : requiredEnv('MS_TENANT_ID');
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/src/setup/config.ts"],"sourcesContent":["/**\n * Microsoft OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Microsoft OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for external use\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * Auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'device-code' | 'dcr';\n\n/**\n * Parse OAuth mode string into auth mode.\n *\n * @param value - OAuth mode string ('loopback-oauth', 'device-code', 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('device-code') // { auth: 'device-code' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n // Validate auth mode\n if (value !== 'loopback-oauth' && value !== 'device-code' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, device-code, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * - 'stdio': Standard input/output transport\n * - 'http': HTTP transport\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Microsoft OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: OAuth mode ('loopback-oauth' | 'device-code' | '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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD client secret (optional for public clients)\n * - AUTH_MODE: OAuth 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 *\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 * @returns Parsed Microsoft 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=device-code'], 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 * - device-code\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 Microsoft 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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse OAuth mode\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 // Parse redirect-uri (CLI overrides ENV)\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 // Parse headless mode\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n clientId,\n tenantId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD 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://graph.microsoft.com/.default'\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://graph.microsoft.com/.default'\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 // Parse CLI arguments\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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse DCR mode (CLI overrides environment)\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 // Validate DCR mode\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n // Parse verify URL (CLI overrides environment)\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 // Parse store URI (CLI overrides environment)\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 // Validate mode-specific required fields\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n tenantId,\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","cliTenantId","tenantId","clientId","clientSecret","MS_CLIENT_SECRET","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-microsoft/src/setup/config.ts"],"sourcesContent":["/**\n * Microsoft OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Microsoft OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for external use\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * Auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'device-code' | 'dcr';\n\n/**\n * Parse OAuth mode string into auth mode.\n *\n * @param value - OAuth mode string ('loopback-oauth', 'device-code', 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('device-code') // { auth: 'device-code' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n // Validate auth mode\n if (value !== 'loopback-oauth' && value !== 'device-code' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, device-code, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * - 'stdio': Standard input/output transport\n * - 'http': HTTP transport\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Microsoft OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: OAuth mode ('loopback-oauth' | 'device-code' | '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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD client secret (optional for public clients)\n * - AUTH_MODE: OAuth 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 *\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 * @returns Parsed Microsoft 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=device-code'], 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 * - device-code\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 Microsoft 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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse OAuth mode\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 // Parse redirect-uri (CLI overrides ENV)\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 // Parse headless mode\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n clientId,\n tenantId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD 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://graph.microsoft.com/.default'\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://graph.microsoft.com/.default'\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 // Parse CLI arguments\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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse DCR mode (CLI overrides environment)\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 // Validate DCR mode\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n // Parse verify URL (CLI overrides environment)\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 // Parse store URI (CLI overrides environment)\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 // Validate mode-specific required fields\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n tenantId,\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","cliTenantId","tenantId","clientId","clientSecret","MS_CLIENT_SECRET","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
  // Apply required middleware for OAuth 2.0 endpoints (RFC 6749)
32
47
  router.use(express.json()); // For /oauth/register (application/json)
33
48
  router.use(express.urlencoded({
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/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 // Apply required middleware for OAuth 2.0 endpoints (RFC 6749)\n router.use(express.json()); // For /oauth/register (application/json)\n router.use(express.urlencoded({ extended: true })); // For /oauth/token (application/x-www-form-urlencoded)\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\n // Register the client\n const client = await dcrUtils.registerClient(store, registrationRequest);\n\n // Return client information (RFC 7591 Section 3.2.1)\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 Microsoft 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 // Validate required parameters\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 // Validate client\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 // Validate redirect_uri\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 // Store DCR request state for Microsoft OAuth callback\n const msState = 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:ms-state:${msState}`, dcrRequestState, 600000); // 10 min TTL\n\n // Build Microsoft authorization URL\n const msAuthUrl = new URL(`https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/authorize`);\n msAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n msAuthUrl.searchParams.set('response_type', 'code');\n msAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n msAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n msAuthUrl.searchParams.set('state', msState);\n msAuthUrl.searchParams.set('response_mode', 'query');\n\n // Redirect user to Microsoft for authorization\n return res.redirect(msAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles callback from Microsoft after user authorization\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: msCode, state: msState, error, error_description } = req.query;\n\n // Handle Microsoft OAuth errors\n if (error) {\n return res.status(400).json({\n error,\n error_description: error_description || 'Microsoft OAuth authorization failed',\n });\n }\n\n if (!msCode || typeof msCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Authorization code is required',\n });\n }\n\n if (!msState || typeof msState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'State parameter is required',\n });\n }\n\n // Retrieve original DCR request state\n const dcrRequestState = await store.get(`dcr:ms-state:${msState}`);\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 // Delete state (one-time use)\n await store.delete(`dcr:ms-state:${msState}`);\n\n // Exchange Microsoft authorization code for tokens\n try {\n const tokenUrl = `https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/token`;\n const tokenParams = new URLSearchParams({\n grant_type: 'authorization_code',\n code: msCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n scope: dcrRequestState.scope,\n });\n\n // Add client_secret if available (confidential client)\n if (clientConfig.clientSecret) {\n tokenParams.set('client_secret', clientConfig.clientSecret);\n }\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 errorData = (await tokenResponse.json()) as { error?: string; error_description?: string };\n throw new Error(`Microsoft token exchange failed: ${errorData.error_description || errorData.error}`);\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 Microsoft 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 // Generate DCR authorization code with real provider tokens\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 // Redirect back to MCP client with DCR authorization code\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 } catch (error) {\n return res.status(500).json({\n error: 'server_error',\n error_description: error instanceof Error ? error.message : 'Failed to exchange authorization code',\n });\n }\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 // Extract client credentials from either body or Basic Auth header\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n // Support client_secret_basic authentication (RFC 6749 Section 2.3.1)\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 // Validate grant_type\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 // Authorization Code Grant\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 // Get authorization code\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 // Validate authorization code\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 // Validate PKCE if used\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 // Validate code_verifier against code_challenge\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 // Delete authorization code (one-time use)\n await dcrUtils.deleteAuthCode(store, code);\n\n // Generate DCR access token\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\n // Store provider tokens indexed by DCR access token\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n // Return token response\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 // Refresh Token Grant\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 // 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 // Get refresh token\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 // Refresh provider tokens if available\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Microsoft tokens\n const provider = new DcrOAuthProvider({\n clientId: clientConfig.clientId,\n ...(clientConfig.clientSecret && { clientSecret: clientConfig.clientSecret }),\n tenantId: clientConfig.tenantId ?? 'common',\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 Microsoft 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 // Generate new DCR access token\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\n // Store refreshed provider tokens indexed by new DCR access token\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 // Validate client if credentials provided\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 // Revoke the token\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 // RFC 7009: Return 200 even if token not found\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 // Extract bearer token from Authorization header\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); // Remove 'Bearer ' prefix\n\n // Validate token exists in access tokens store\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 // Check if token is expired\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n // Remove expired token\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 // Return AuthInfo with provider tokens for stateless DCR\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 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","msState","dcrRequestState","undefined","created_at","Date","now","expires_at","set","msAuthUrl","URL","tenantId","searchParams","clientId","redirect","toString","code","msCode","delete","tokenUrl","tokenParams","URLSearchParams","grant_type","clientSecret","tokenResponse","fetch","method","headers","ok","errorData","tokenData","providerTokens","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","dcrCode","authCode","setAuthCode","clientRedirectUrl","client_secret","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-microsoft/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 // Apply required middleware for OAuth 2.0 endpoints (RFC 6749)\n router.use(express.json()); // For /oauth/register (application/json)\n router.use(express.urlencoded({ extended: true })); // For /oauth/token (application/x-www-form-urlencoded)\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\n // Register the client\n const client = await dcrUtils.registerClient(store, registrationRequest);\n\n // Return client information (RFC 7591 Section 3.2.1)\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 Microsoft 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 // Validate required parameters\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 // Validate client\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 // Validate redirect_uri\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 // Store DCR request state for Microsoft OAuth callback\n const msState = 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:ms-state:${msState}`, dcrRequestState, 600000); // 10 min TTL\n\n // Build Microsoft authorization URL\n const msAuthUrl = new URL(`https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/authorize`);\n msAuthUrl.searchParams.set('client_id', clientConfig.clientId);\n msAuthUrl.searchParams.set('response_type', 'code');\n msAuthUrl.searchParams.set('redirect_uri', `${baseUrl}/oauth/callback`);\n msAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');\n msAuthUrl.searchParams.set('state', msState);\n msAuthUrl.searchParams.set('response_mode', 'query');\n\n // Redirect user to Microsoft for authorization\n return res.redirect(msAuthUrl.toString());\n });\n\n /**\n * OAuth Callback Handler\n * GET /oauth/callback\n *\n * Handles callback from Microsoft after user authorization\n */\n router.get('/oauth/callback', async (req: Request, res: Response) => {\n const { code: msCode, state: msState, error, error_description } = req.query;\n\n // Handle Microsoft OAuth errors\n if (error) {\n return res.status(400).json({\n error,\n error_description: error_description || 'Microsoft OAuth authorization failed',\n });\n }\n\n if (!msCode || typeof msCode !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'Authorization code is required',\n });\n }\n\n if (!msState || typeof msState !== 'string') {\n return res.status(400).json({\n error: 'invalid_request',\n error_description: 'State parameter is required',\n });\n }\n\n // Retrieve original DCR request state\n const dcrRequestState = await store.get(`dcr:ms-state:${msState}`);\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 // Delete state (one-time use)\n await store.delete(`dcr:ms-state:${msState}`);\n\n // Exchange Microsoft authorization code for tokens\n try {\n const tokenUrl = `https://login.microsoftonline.com/${clientConfig.tenantId || 'common'}/oauth2/v2.0/token`;\n const tokenParams = new URLSearchParams({\n grant_type: 'authorization_code',\n code: msCode,\n client_id: clientConfig.clientId,\n redirect_uri: `${baseUrl}/oauth/callback`,\n scope: dcrRequestState.scope,\n });\n\n // Add client_secret if available (confidential client)\n if (clientConfig.clientSecret) {\n tokenParams.set('client_secret', clientConfig.clientSecret);\n }\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 errorData = (await tokenResponse.json()) as { error?: string; error_description?: string };\n throw new Error(`Microsoft token exchange failed: ${errorData.error_description || errorData.error}`);\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 Microsoft 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 // Generate DCR authorization code with real provider tokens\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 // Redirect back to MCP client with DCR authorization code\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 } catch (error) {\n return res.status(500).json({\n error: 'server_error',\n error_description: error instanceof Error ? error.message : 'Failed to exchange authorization code',\n });\n }\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 // Extract client credentials from either body or Basic Auth header\n let client_id = req.body.client_id;\n let client_secret = req.body.client_secret;\n\n // Support client_secret_basic authentication (RFC 6749 Section 2.3.1)\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 // Validate grant_type\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 // Authorization Code Grant\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 // Get authorization code\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 // Validate authorization code\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 // Validate PKCE if used\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 // Validate code_verifier against code_challenge\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 // Delete authorization code (one-time use)\n await dcrUtils.deleteAuthCode(store, code);\n\n // Generate DCR access token\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\n // Store provider tokens indexed by DCR access token\n await dcrUtils.setProviderTokens(store, accessToken, authCode.providerTokens);\n\n // Return token response\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 // Refresh Token Grant\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 // 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 // Get refresh token\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 // Refresh provider tokens if available\n let refreshedProviderTokens = tokenData.providerTokens;\n if (tokenData.providerTokens.refreshToken) {\n try {\n // Create DcrOAuthProvider instance to refresh Microsoft tokens\n const provider = new DcrOAuthProvider({\n clientId: clientConfig.clientId,\n ...(clientConfig.clientSecret && { clientSecret: clientConfig.clientSecret }),\n tenantId: clientConfig.tenantId ?? 'common',\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 Microsoft 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 // Generate new DCR access token\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\n // Store refreshed provider tokens indexed by new DCR access token\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 // Validate client if credentials provided\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 // Revoke the token\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 // RFC 7009: Return 200 even if token not found\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 // Extract bearer token from Authorization header\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); // Remove 'Bearer ' prefix\n\n // Validate token exists in access tokens store\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 // Check if token is expired\n const now = Date.now();\n const expiresAt = tokenData.created_at + tokenData.expires_in * 1000;\n\n if (now > expiresAt) {\n // Remove expired token\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 // Return AuthInfo with provider tokens for stateless DCR\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 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","msState","dcrRequestState","undefined","created_at","Date","now","expires_at","msAuthUrl","URL","tenantId","searchParams","clientId","redirect","toString","msCode","delete","tokenUrl","tokenParams","URLSearchParams","grant_type","clientSecret","tokenResponse","fetch","method","ok","errorData","tokenData","providerTokens","accessToken","access_token","refresh_token","refreshToken","expiresAt","expires_in","dcrCode","authCode","setAuthCode","clientRedirectUrl","client_secret","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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"}
@@ -128,9 +128,10 @@
128
128
  throw new Error('REDIRECT_URI requires HTTP transport. The OAuth callback must be served over HTTP.');
129
129
  }
130
130
  // Parse headless mode
131
- const cliHeadless = typeof values.headless === 'boolean' ? values.headless : undefined;
131
+ if (typeof values.headless === 'string') throw new Error('Use --headless or --no-headless (do not pass a value)');
132
+ const cliHeadless = values['no-headless'] ? false : values.headless === true ? true : undefined;
132
133
  const envHeadless = env.HEADLESS === 'true' ? true : env.HEADLESS === 'false' ? false : undefined;
133
- const headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined; // default for redirectUri is headless (assume server http deployment); otherwise assume local and non-headless
134
+ const headless = (_ref = cliHeadless !== null && cliHeadless !== void 0 ? cliHeadless : envHeadless) !== null && _ref !== void 0 ? _ref : redirectUri !== undefined;
134
135
  // Parse tenant-id (CLI overrides environment)
135
136
  const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;
136
137
  const tenantId = cliTenantId !== null && cliTenantId !== void 0 ? cliTenantId : requiredEnv('MS_TENANT_ID');
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/src/setup/config.ts"],"sourcesContent":["/**\n * Microsoft OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Microsoft OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for external use\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * Auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'device-code' | 'dcr';\n\n/**\n * Parse OAuth mode string into auth mode.\n *\n * @param value - OAuth mode string ('loopback-oauth', 'device-code', 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('device-code') // { auth: 'device-code' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n // Validate auth mode\n if (value !== 'loopback-oauth' && value !== 'device-code' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, device-code, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * - 'stdio': Standard input/output transport\n * - 'http': HTTP transport\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Microsoft OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: OAuth mode ('loopback-oauth' | 'device-code' | '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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD client secret (optional for public clients)\n * - AUTH_MODE: OAuth 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 *\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 * @returns Parsed Microsoft 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=device-code'], 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 * - device-code\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 Microsoft 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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse OAuth mode\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 // Parse redirect-uri (CLI overrides ENV)\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 // Parse headless mode\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n clientId,\n tenantId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD 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://graph.microsoft.com/.default'\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://graph.microsoft.com/.default'\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 // Parse CLI arguments\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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse DCR mode (CLI overrides environment)\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 // Validate DCR mode\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n // Parse verify URL (CLI overrides environment)\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 // Parse store URI (CLI overrides environment)\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 // Validate mode-specific required fields\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n tenantId,\n scope,\n };\n}\n"],"names":["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","cliTenantId","tenantId","clientId","clientSecret","MS_CLIENT_SECRET","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-microsoft/src/setup/config.ts"],"sourcesContent":["/**\n * Microsoft OAuth configuration parsing from CLI arguments and environment variables.\n *\n * This module provides utilities to parse Microsoft OAuth configuration from\n * CLI arguments and environment variables, following the same pattern as @mcp-z/server's\n * parseConfig().\n */\n\nimport { parseArgs } from 'util';\nimport type { DcrConfig, OAuthConfig } from '../types.ts';\n\n// Re-export for external use\nexport type { DcrConfig, OAuthConfig };\n\n/**\n * Auth mode type (from OAuthConfig)\n */\ntype AuthMode = 'loopback-oauth' | 'device-code' | 'dcr';\n\n/**\n * Parse OAuth mode string into auth mode.\n *\n * @param value - OAuth mode string ('loopback-oauth', 'device-code', 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('device-code') // { auth: 'device-code' }\n * parseAuthMode('dcr') // { auth: 'dcr' }\n * ```\n */\nfunction parseAuthMode(value: string): {\n auth: AuthMode;\n} {\n // Validate auth mode\n if (value !== 'loopback-oauth' && value !== 'device-code' && value !== 'dcr') {\n throw new Error(`Invalid --auth value: \"${value}\". Valid values: loopback-oauth, device-code, dcr`);\n }\n\n return {\n auth: value as AuthMode,\n };\n}\n\n/**\n * Transport type for MCP servers\n *\n * - 'stdio': Standard input/output transport\n * - 'http': HTTP transport\n */\nexport type TransportType = 'stdio' | 'http';\n\n/**\n * Parse Microsoft OAuth configuration from CLI arguments and environment variables.\n *\n * CLI Arguments:\n * - --auth: OAuth mode ('loopback-oauth' | 'device-code' | '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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD client secret (optional for public clients)\n * - AUTH_MODE: OAuth 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 *\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 * @returns Parsed Microsoft 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=device-code'], 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 * - device-code\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 Microsoft 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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse OAuth mode\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 // Parse redirect-uri (CLI overrides ENV)\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 // Parse headless mode\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n clientId,\n tenantId,\n ...(clientSecret && { clientSecret }),\n auth,\n headless,\n ...(redirectUri && { redirectUri }),\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 * - --tenant-id: Override Microsoft tenant ID\n *\n * Required environment variables:\n * - MS_CLIENT_ID: Azure AD application (client) ID\n * - MS_TENANT_ID: Azure AD tenant ID ('common', 'organizations', 'consumers', or tenant GUID)\n *\n * Optional environment variables:\n * - MS_CLIENT_SECRET: Azure AD 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://graph.microsoft.com/.default'\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://graph.microsoft.com/.default'\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 // Parse CLI arguments\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 'tenant-id': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n // Parse DCR mode (CLI overrides environment)\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 // Validate DCR mode\n if (mode !== 'self-hosted' && mode !== 'external') {\n throw new Error(`Invalid --dcr-mode value: \"${mode}\". Valid values: self-hosted, external`);\n }\n\n // Parse verify URL (CLI overrides environment)\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 // Parse store URI (CLI overrides environment)\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 // Validate mode-specific required fields\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 // Parse tenant-id (CLI overrides environment)\n const cliTenantId = typeof values['tenant-id'] === 'string' ? values['tenant-id'] : undefined;\n const tenantId = cliTenantId ?? requiredEnv('MS_TENANT_ID');\n\n // Parse credentials\n const clientId = requiredEnv('MS_CLIENT_ID');\n const clientSecret = env.MS_CLIENT_SECRET;\n\n return {\n mode,\n ...(verifyUrl && { verifyUrl }),\n ...(storeUri && { storeUri }),\n clientId,\n ...(clientSecret && { clientSecret }),\n tenantId,\n scope,\n };\n}\n"],"names":["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","cliTenantId","tenantId","clientId","clientSecret","MS_CLIENT_SECRET","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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-z/oauth-microsoft",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "OAuth 2.0 client for Microsoft Graph with multi-account support, PKCE security, and swappable storage backends",
5
5
  "keywords": [
6
6
  "oauth2",
@@ -52,27 +52,27 @@
52
52
  "version": "tsds version"
53
53
  },
54
54
  "dependencies": {
55
- "@mcp-z/oauth": "^1.0.0",
56
- "express": "^5.0.0",
55
+ "@mcp-z/oauth": "^1.0.1",
56
+ "express": "^5.2.1",
57
57
  "open": "^11.0.0",
58
- "zod": "^4.0.0"
58
+ "zod": "^4.3.4"
59
59
  },
60
60
  "devDependencies": {
61
- "@mcp-z/client": "^1.0.0",
61
+ "@mcp-z/client": "^1.0.4",
62
62
  "@microsoft/microsoft-graph-client": "^3.0.7",
63
- "@modelcontextprotocol/sdk": "^1.0.0",
63
+ "@modelcontextprotocol/sdk": "^1.25.1",
64
64
  "@types/cors": "^2.8.19",
65
65
  "@types/express": "^5.0.6",
66
66
  "@types/mocha": "^10.0.10",
67
- "@types/node": "^25.0.2",
68
- "cors": "^2.0.0",
67
+ "@types/node": "^25.0.3",
68
+ "cors": "^2.8.5",
69
69
  "dotenv": "^17.2.3",
70
70
  "get-port": "^7.1.0",
71
71
  "keyv": "^5.5.5",
72
72
  "keyv-file": "^5.3.3",
73
- "node-version-use": "^2.1.6",
74
- "ts-dev-stack": "^1.21.3",
75
- "tsds-config": "^1.0.0",
73
+ "node-version-use": "^2.4.7",
74
+ "ts-dev-stack": "^1.22.1",
75
+ "tsds-config": "^1.0.4",
76
76
  "typescript": "^5.9.3"
77
77
  },
78
78
  "peerDependencies": {