@mcp-z/oauth-microsoft 1.0.4 → 1.0.5

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.
@@ -380,6 +380,9 @@ function _ts_generator(thisArg, body) {
380
380
  };
381
381
  }
382
382
  }
383
+ var TEN_MINUTES_MS = 10 * 60 * 1000;
384
+ var ONE_HOUR_MS = 60 * 60 * 1000;
385
+ var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
383
386
  function registerClient(store, metadata) {
384
387
  return _async_to_generator(function() {
385
388
  var _metadata_grant_types, _metadata_response_types, _metadata_token_endpoint_auth_method, client_id, client_secret, grant_types, response_types, client, created_at, clientInfo;
@@ -648,7 +651,7 @@ function setProviderTokens(store, dcrToken, tokens) {
648
651
  case 0:
649
652
  return [
650
653
  4,
651
- store.set("dcr:provider:".concat(dcrToken), tokens)
654
+ store.set("dcr:provider:".concat(dcrToken), tokens, ONE_HOUR_MS)
652
655
  ];
653
656
  case 1:
654
657
  _state.sent();
@@ -702,7 +705,7 @@ function setAuthCode(store, code, authCode) {
702
705
  case 0:
703
706
  return [
704
707
  4,
705
- store.set("dcr:authcode:".concat(code), authCode)
708
+ store.set("dcr:authcode:".concat(code), authCode, TEN_MINUTES_MS)
706
709
  ];
707
710
  case 1:
708
711
  _state.sent();
@@ -756,7 +759,7 @@ function setAccessToken(store, token, tokenData) {
756
759
  case 0:
757
760
  return [
758
761
  4,
759
- store.set("dcr:access:".concat(token), tokenData)
762
+ store.set("dcr:access:".concat(token), tokenData, ONE_HOUR_MS)
760
763
  ];
761
764
  case 1:
762
765
  _state.sent();
@@ -810,7 +813,7 @@ function setRefreshToken(store, token, tokenData) {
810
813
  case 0:
811
814
  return [
812
815
  4,
813
- store.set("dcr:refresh:".concat(token), tokenData)
816
+ store.set("dcr:refresh:".concat(token), tokenData, THIRTY_DAYS_MS)
814
817
  ];
815
818
  case 1:
816
819
  _state.sent();
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/src/lib/dcr-utils.ts"],"sourcesContent":["/**\n * DCR Storage Utilities\n *\n * Keyv-based storage utilities for Dynamic Client Registration.\n * Follows @mcp-z/oauth pattern: single Keyv store with compound keys.\n *\n * Key Patterns:\n * - dcr:client:{clientId} -> RegisteredClient\n * - dcr:provider:{dcrToken} -> ProviderTokens\n * - dcr:authcode:{code} -> AuthorizationCode\n * - dcr:access:{token} -> AccessToken\n * - dcr:refresh:{token} -> AccessToken\n */\n\nimport type { DcrClientInformation, DcrClientMetadata, ProviderTokens } from '@mcp-z/oauth';\nimport { randomUUID } from 'crypto';\nimport type { Keyv } from 'keyv';\nimport type { AccessToken, AuthorizationCode, RegisteredClient } from '../types.ts';\n\n// ============================================================================\n// Client Operations\n// ============================================================================\n\n/**\n * Register a new OAuth client (RFC 7591 Section 3.1)\n *\n * @param store - Keyv store for all DCR data\n * @param metadata - Client registration metadata\n * @returns Registered client with credentials\n * @throws Error if validation fails\n */\nexport async function registerClient(store: Keyv, metadata: DcrClientMetadata): Promise<DcrClientInformation> {\n // Validate redirect URIs (required per RFC 7591)\n if (!metadata.redirect_uris || metadata.redirect_uris.length === 0) {\n throw new Error('redirect_uris is required');\n }\n\n // Generate client credentials\n const client_id = `dcr_${randomUUID()}`;\n const client_secret = randomUUID();\n\n // Default grant types and response types per RFC 7591 Section 2\n const grant_types = metadata.grant_types ?? ['authorization_code', 'refresh_token'];\n const response_types = metadata.response_types ?? ['code'];\n\n // Build registered client - only include optional fields if they have values\n const client: RegisteredClient = {\n client_id,\n client_secret,\n client_id_issued_at: Math.floor(Date.now() / 1000),\n client_secret_expires_at: 0, // Never expires\n redirect_uris: metadata.redirect_uris,\n token_endpoint_auth_method: metadata.token_endpoint_auth_method ?? 'client_secret_basic',\n grant_types,\n response_types,\n ...(metadata.client_name !== undefined && { client_name: metadata.client_name }),\n ...(metadata.client_uri !== undefined && { client_uri: metadata.client_uri }),\n ...(metadata.logo_uri !== undefined && { logo_uri: metadata.logo_uri }),\n ...(metadata.scope !== undefined && { scope: metadata.scope }),\n ...(metadata.contacts !== undefined && { contacts: metadata.contacts }),\n ...(metadata.tos_uri !== undefined && { tos_uri: metadata.tos_uri }),\n ...(metadata.policy_uri !== undefined && { policy_uri: metadata.policy_uri }),\n ...(metadata.jwks_uri !== undefined && { jwks_uri: metadata.jwks_uri }),\n ...(metadata.jwks !== undefined && { jwks: metadata.jwks }),\n ...(metadata.software_id !== undefined && { software_id: metadata.software_id }),\n ...(metadata.software_version !== undefined && { software_version: metadata.software_version }),\n created_at: Date.now(),\n };\n\n // Store client\n await store.set(`dcr:client:${client_id}`, client);\n\n // Return client information (excluding internal created_at)\n const { created_at, ...clientInfo } = client;\n return clientInfo;\n}\n\n/**\n * Get a registered client by ID\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @returns Registered client or undefined if not found\n */\nexport async function getClient(store: Keyv, clientId: string): Promise<RegisteredClient | undefined> {\n return await store.get(`dcr:client:${clientId}`);\n}\n\n/**\n * Validate client credentials\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param clientSecret - Client secret\n * @returns True if credentials are valid\n */\nexport async function validateClient(store: Keyv, clientId: string, clientSecret: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client) return false;\n return client.client_secret === clientSecret;\n}\n\n/**\n * Validate redirect URI for a client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param redirectUri - Redirect URI to validate\n * @returns True if redirect URI is registered\n */\nexport async function validateRedirectUri(store: Keyv, clientId: string, redirectUri: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client || !client.redirect_uris) return false;\n return client.redirect_uris.includes(redirectUri);\n}\n\n/**\n * List all registered clients (for debugging)\n *\n * Note: This method uses Keyv's iterator which may not be available on all storage adapters.\n * For production use, consider maintaining a separate index of client IDs.\n *\n * @param store - Keyv store for all DCR data\n * @returns Array of all registered clients\n */\nexport async function listClients(store: Keyv): Promise<RegisteredClient[]> {\n const clients: RegisteredClient[] = [];\n\n // Check if iterator is available on the store\n if (store.iterator) {\n // Use iterator with namespace to iterate through dcr:client: keys\n const iterator = store.iterator('dcr:client:');\n for await (const [_key, value] of iterator) {\n if (value !== undefined) {\n clients.push(value as RegisteredClient);\n }\n }\n }\n\n return clients;\n}\n\n/**\n * Delete a registered client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n */\nexport async function deleteClient(store: Keyv, clientId: string): Promise<void> {\n await store.delete(`dcr:client:${clientId}`);\n}\n\n// ============================================================================\n// Provider Token Operations\n// ============================================================================\n\n/**\n * Store provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token (used as key)\n * @param tokens - Microsoft provider tokens (access, refresh, expiry)\n */\nexport async function setProviderTokens(store: Keyv, dcrToken: string, tokens: ProviderTokens): Promise<void> {\n await store.set(`dcr:provider:${dcrToken}`, tokens);\n}\n\n/**\n * Retrieve provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n * @returns Provider tokens or undefined if not found\n */\nexport async function getProviderTokens(store: Keyv, dcrToken: string): Promise<ProviderTokens | undefined> {\n return await store.get(`dcr:provider:${dcrToken}`);\n}\n\n/**\n * Delete provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n */\nexport async function deleteProviderTokens(store: Keyv, dcrToken: string): Promise<void> {\n await store.delete(`dcr:provider:${dcrToken}`);\n}\n\n// ============================================================================\n// Authorization Code Operations\n// ============================================================================\n\n/**\n * Store an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @param authCode - Authorization code data\n */\nexport async function setAuthCode(store: Keyv, code: string, authCode: AuthorizationCode): Promise<void> {\n await store.set(`dcr:authcode:${code}`, authCode);\n}\n\n/**\n * Get an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @returns Authorization code data or undefined if not found\n */\nexport async function getAuthCode(store: Keyv, code: string): Promise<AuthorizationCode | undefined> {\n return await store.get(`dcr:authcode:${code}`);\n}\n\n/**\n * Delete an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n */\nexport async function deleteAuthCode(store: Keyv, code: string): Promise<void> {\n await store.delete(`dcr:authcode:${code}`);\n}\n\n// ============================================================================\n// Access Token Operations\n// ============================================================================\n\n/**\n * Store an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @param tokenData - Access token data\n */\nexport async function setAccessToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:access:${token}`, tokenData);\n}\n\n/**\n * Get an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @returns Access token data or undefined if not found\n */\nexport async function getAccessToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:access:${token}`);\n}\n\n/**\n * Delete an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n */\nexport async function deleteAccessToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:access:${token}`);\n}\n\n// ============================================================================\n// Refresh Token Operations\n// ============================================================================\n\n/**\n * Store a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @param tokenData - Access token data (contains refresh token context)\n */\nexport async function setRefreshToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:refresh:${token}`, tokenData);\n}\n\n/**\n * Get a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @returns Access token data or undefined if not found\n */\nexport async function getRefreshToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:refresh:${token}`);\n}\n\n/**\n * Delete a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n */\nexport async function deleteRefreshToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:refresh:${token}`);\n}\n"],"names":["deleteAccessToken","deleteAuthCode","deleteClient","deleteProviderTokens","deleteRefreshToken","getAccessToken","getAuthCode","getClient","getProviderTokens","getRefreshToken","listClients","registerClient","setAccessToken","setAuthCode","setProviderTokens","setRefreshToken","validateClient","validateRedirectUri","store","metadata","client_id","client_secret","grant_types","response_types","client","created_at","clientInfo","redirect_uris","length","Error","randomUUID","client_id_issued_at","Math","floor","Date","now","client_secret_expires_at","token_endpoint_auth_method","client_name","undefined","client_uri","logo_uri","scope","contacts","tos_uri","policy_uri","jwks_uri","jwks","software_id","software_version","set","clientId","get","clientSecret","redirectUri","includes","clients","iterator","_key","value","push","delete","dcrToken","tokens","code","authCode","token","tokenData"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/src/lib/dcr-utils.ts"],"sourcesContent":["/**\n * DCR Storage Utilities\n *\n * Keyv-based storage utilities for Dynamic Client Registration.\n * Follows @mcp-z/oauth pattern: single Keyv store with compound keys.\n *\n * Key Patterns:\n * - dcr:client:{clientId} -> RegisteredClient\n * - dcr:provider:{dcrToken} -> ProviderTokens\n * - dcr:authcode:{code} -> AuthorizationCode\n * - dcr:access:{token} -> AccessToken\n * - dcr:refresh:{token} -> AccessToken\n */\n\nimport type { DcrClientInformation, DcrClientMetadata, ProviderTokens } from '@mcp-z/oauth';\nimport { randomUUID } from 'crypto';\nimport type { Keyv } from 'keyv';\nimport type { AccessToken, AuthorizationCode, RegisteredClient } from '../types.ts';\n\nconst TEN_MINUTES_MS = 10 * 60 * 1000;\nconst ONE_HOUR_MS = 60 * 60 * 1000;\nconst THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;\n\n// ============================================================================\n// Client Operations\n// ============================================================================\n\n/**\n * Register a new OAuth client (RFC 7591 Section 3.1)\n *\n * @param store - Keyv store for all DCR data\n * @param metadata - Client registration metadata\n * @returns Registered client with credentials\n * @throws Error if validation fails\n */\nexport async function registerClient(store: Keyv, metadata: DcrClientMetadata): Promise<DcrClientInformation> {\n // Validate redirect URIs (required per RFC 7591)\n if (!metadata.redirect_uris || metadata.redirect_uris.length === 0) {\n throw new Error('redirect_uris is required');\n }\n\n // Generate client credentials\n const client_id = `dcr_${randomUUID()}`;\n const client_secret = randomUUID();\n\n // Default grant types and response types per RFC 7591 Section 2\n const grant_types = metadata.grant_types ?? ['authorization_code', 'refresh_token'];\n const response_types = metadata.response_types ?? ['code'];\n\n // Build registered client - only include optional fields if they have values\n const client: RegisteredClient = {\n client_id,\n client_secret,\n client_id_issued_at: Math.floor(Date.now() / 1000),\n client_secret_expires_at: 0, // Never expires\n redirect_uris: metadata.redirect_uris,\n token_endpoint_auth_method: metadata.token_endpoint_auth_method ?? 'client_secret_basic',\n grant_types,\n response_types,\n ...(metadata.client_name !== undefined && { client_name: metadata.client_name }),\n ...(metadata.client_uri !== undefined && { client_uri: metadata.client_uri }),\n ...(metadata.logo_uri !== undefined && { logo_uri: metadata.logo_uri }),\n ...(metadata.scope !== undefined && { scope: metadata.scope }),\n ...(metadata.contacts !== undefined && { contacts: metadata.contacts }),\n ...(metadata.tos_uri !== undefined && { tos_uri: metadata.tos_uri }),\n ...(metadata.policy_uri !== undefined && { policy_uri: metadata.policy_uri }),\n ...(metadata.jwks_uri !== undefined && { jwks_uri: metadata.jwks_uri }),\n ...(metadata.jwks !== undefined && { jwks: metadata.jwks }),\n ...(metadata.software_id !== undefined && { software_id: metadata.software_id }),\n ...(metadata.software_version !== undefined && { software_version: metadata.software_version }),\n created_at: Date.now(),\n };\n\n // Store client\n await store.set(`dcr:client:${client_id}`, client);\n\n // Return client information (excluding internal created_at)\n const { created_at, ...clientInfo } = client;\n return clientInfo;\n}\n\n/**\n * Get a registered client by ID\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @returns Registered client or undefined if not found\n */\nexport async function getClient(store: Keyv, clientId: string): Promise<RegisteredClient | undefined> {\n return await store.get(`dcr:client:${clientId}`);\n}\n\n/**\n * Validate client credentials\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param clientSecret - Client secret\n * @returns True if credentials are valid\n */\nexport async function validateClient(store: Keyv, clientId: string, clientSecret: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client) return false;\n return client.client_secret === clientSecret;\n}\n\n/**\n * Validate redirect URI for a client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param redirectUri - Redirect URI to validate\n * @returns True if redirect URI is registered\n */\nexport async function validateRedirectUri(store: Keyv, clientId: string, redirectUri: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client || !client.redirect_uris) return false;\n return client.redirect_uris.includes(redirectUri);\n}\n\n/**\n * List all registered clients (for debugging)\n *\n * Note: This method uses Keyv's iterator which may not be available on all storage adapters.\n * For production use, consider maintaining a separate index of client IDs.\n *\n * @param store - Keyv store for all DCR data\n * @returns Array of all registered clients\n */\nexport async function listClients(store: Keyv): Promise<RegisteredClient[]> {\n const clients: RegisteredClient[] = [];\n\n // Check if iterator is available on the store\n if (store.iterator) {\n // Use iterator with namespace to iterate through dcr:client: keys\n const iterator = store.iterator('dcr:client:');\n for await (const [_key, value] of iterator) {\n if (value !== undefined) {\n clients.push(value as RegisteredClient);\n }\n }\n }\n\n return clients;\n}\n\n/**\n * Delete a registered client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n */\nexport async function deleteClient(store: Keyv, clientId: string): Promise<void> {\n await store.delete(`dcr:client:${clientId}`);\n}\n\n// ============================================================================\n// Provider Token Operations\n// ============================================================================\n\n/**\n * Store provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token (used as key)\n * @param tokens - Microsoft provider tokens (access, refresh, expiry)\n */\nexport async function setProviderTokens(store: Keyv, dcrToken: string, tokens: ProviderTokens): Promise<void> {\n await store.set(`dcr:provider:${dcrToken}`, tokens, ONE_HOUR_MS);\n}\n\n/**\n * Retrieve provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n * @returns Provider tokens or undefined if not found\n */\nexport async function getProviderTokens(store: Keyv, dcrToken: string): Promise<ProviderTokens | undefined> {\n return await store.get(`dcr:provider:${dcrToken}`);\n}\n\n/**\n * Delete provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n */\nexport async function deleteProviderTokens(store: Keyv, dcrToken: string): Promise<void> {\n await store.delete(`dcr:provider:${dcrToken}`);\n}\n\n// ============================================================================\n// Authorization Code Operations\n// ============================================================================\n\n/**\n * Store an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @param authCode - Authorization code data\n */\nexport async function setAuthCode(store: Keyv, code: string, authCode: AuthorizationCode): Promise<void> {\n await store.set(`dcr:authcode:${code}`, authCode, TEN_MINUTES_MS);\n}\n\n/**\n * Get an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @returns Authorization code data or undefined if not found\n */\nexport async function getAuthCode(store: Keyv, code: string): Promise<AuthorizationCode | undefined> {\n return await store.get(`dcr:authcode:${code}`);\n}\n\n/**\n * Delete an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n */\nexport async function deleteAuthCode(store: Keyv, code: string): Promise<void> {\n await store.delete(`dcr:authcode:${code}`);\n}\n\n// ============================================================================\n// Access Token Operations\n// ============================================================================\n\n/**\n * Store an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @param tokenData - Access token data\n */\nexport async function setAccessToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:access:${token}`, tokenData, ONE_HOUR_MS);\n}\n\n/**\n * Get an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @returns Access token data or undefined if not found\n */\nexport async function getAccessToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:access:${token}`);\n}\n\n/**\n * Delete an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n */\nexport async function deleteAccessToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:access:${token}`);\n}\n\n// ============================================================================\n// Refresh Token Operations\n// ============================================================================\n\n/**\n * Store a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @param tokenData - Access token data (contains refresh token context)\n */\nexport async function setRefreshToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:refresh:${token}`, tokenData, THIRTY_DAYS_MS);\n}\n\n/**\n * Get a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @returns Access token data or undefined if not found\n */\nexport async function getRefreshToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:refresh:${token}`);\n}\n\n/**\n * Delete a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n */\nexport async function deleteRefreshToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:refresh:${token}`);\n}\n"],"names":["deleteAccessToken","deleteAuthCode","deleteClient","deleteProviderTokens","deleteRefreshToken","getAccessToken","getAuthCode","getClient","getProviderTokens","getRefreshToken","listClients","registerClient","setAccessToken","setAuthCode","setProviderTokens","setRefreshToken","validateClient","validateRedirectUri","TEN_MINUTES_MS","ONE_HOUR_MS","THIRTY_DAYS_MS","store","metadata","client_id","client_secret","grant_types","response_types","client","created_at","clientInfo","redirect_uris","length","Error","randomUUID","client_id_issued_at","Math","floor","Date","now","client_secret_expires_at","token_endpoint_auth_method","client_name","undefined","client_uri","logo_uri","scope","contacts","tos_uri","policy_uri","jwks_uri","jwks","software_id","software_version","set","clientId","get","clientSecret","redirectUri","includes","clients","iterator","_key","value","push","delete","dcrToken","tokens","code","authCode","token","tokenData"],"mappings":"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"}
@@ -11,6 +11,9 @@
11
11
  * - dcr:access:{token} -> AccessToken
12
12
  * - dcr:refresh:{token} -> AccessToken
13
13
  */ import { randomUUID } from 'crypto';
14
+ const TEN_MINUTES_MS = 10 * 60 * 1000;
15
+ const ONE_HOUR_MS = 60 * 60 * 1000;
16
+ const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
14
17
  // ============================================================================
15
18
  // Client Operations
16
19
  // ============================================================================
@@ -162,7 +165,7 @@
162
165
  * @param dcrToken - DCR-issued access token (used as key)
163
166
  * @param tokens - Microsoft provider tokens (access, refresh, expiry)
164
167
  */ export async function setProviderTokens(store, dcrToken, tokens) {
165
- await store.set(`dcr:provider:${dcrToken}`, tokens);
168
+ await store.set(`dcr:provider:${dcrToken}`, tokens, ONE_HOUR_MS);
166
169
  }
167
170
  /**
168
171
  * Retrieve provider tokens for a DCR access token
@@ -191,7 +194,7 @@
191
194
  * @param code - Authorization code
192
195
  * @param authCode - Authorization code data
193
196
  */ export async function setAuthCode(store, code, authCode) {
194
- await store.set(`dcr:authcode:${code}`, authCode);
197
+ await store.set(`dcr:authcode:${code}`, authCode, TEN_MINUTES_MS);
195
198
  }
196
199
  /**
197
200
  * Get an authorization code
@@ -220,7 +223,7 @@
220
223
  * @param token - Access token
221
224
  * @param tokenData - Access token data
222
225
  */ export async function setAccessToken(store, token, tokenData) {
223
- await store.set(`dcr:access:${token}`, tokenData);
226
+ await store.set(`dcr:access:${token}`, tokenData, ONE_HOUR_MS);
224
227
  }
225
228
  /**
226
229
  * Get an access token
@@ -249,7 +252,7 @@
249
252
  * @param token - Refresh token
250
253
  * @param tokenData - Access token data (contains refresh token context)
251
254
  */ export async function setRefreshToken(store, token, tokenData) {
252
- await store.set(`dcr:refresh:${token}`, tokenData);
255
+ await store.set(`dcr:refresh:${token}`, tokenData, THIRTY_DAYS_MS);
253
256
  }
254
257
  /**
255
258
  * Get a refresh token
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/src/lib/dcr-utils.ts"],"sourcesContent":["/**\n * DCR Storage Utilities\n *\n * Keyv-based storage utilities for Dynamic Client Registration.\n * Follows @mcp-z/oauth pattern: single Keyv store with compound keys.\n *\n * Key Patterns:\n * - dcr:client:{clientId} -> RegisteredClient\n * - dcr:provider:{dcrToken} -> ProviderTokens\n * - dcr:authcode:{code} -> AuthorizationCode\n * - dcr:access:{token} -> AccessToken\n * - dcr:refresh:{token} -> AccessToken\n */\n\nimport type { DcrClientInformation, DcrClientMetadata, ProviderTokens } from '@mcp-z/oauth';\nimport { randomUUID } from 'crypto';\nimport type { Keyv } from 'keyv';\nimport type { AccessToken, AuthorizationCode, RegisteredClient } from '../types.ts';\n\n// ============================================================================\n// Client Operations\n// ============================================================================\n\n/**\n * Register a new OAuth client (RFC 7591 Section 3.1)\n *\n * @param store - Keyv store for all DCR data\n * @param metadata - Client registration metadata\n * @returns Registered client with credentials\n * @throws Error if validation fails\n */\nexport async function registerClient(store: Keyv, metadata: DcrClientMetadata): Promise<DcrClientInformation> {\n // Validate redirect URIs (required per RFC 7591)\n if (!metadata.redirect_uris || metadata.redirect_uris.length === 0) {\n throw new Error('redirect_uris is required');\n }\n\n // Generate client credentials\n const client_id = `dcr_${randomUUID()}`;\n const client_secret = randomUUID();\n\n // Default grant types and response types per RFC 7591 Section 2\n const grant_types = metadata.grant_types ?? ['authorization_code', 'refresh_token'];\n const response_types = metadata.response_types ?? ['code'];\n\n // Build registered client - only include optional fields if they have values\n const client: RegisteredClient = {\n client_id,\n client_secret,\n client_id_issued_at: Math.floor(Date.now() / 1000),\n client_secret_expires_at: 0, // Never expires\n redirect_uris: metadata.redirect_uris,\n token_endpoint_auth_method: metadata.token_endpoint_auth_method ?? 'client_secret_basic',\n grant_types,\n response_types,\n ...(metadata.client_name !== undefined && { client_name: metadata.client_name }),\n ...(metadata.client_uri !== undefined && { client_uri: metadata.client_uri }),\n ...(metadata.logo_uri !== undefined && { logo_uri: metadata.logo_uri }),\n ...(metadata.scope !== undefined && { scope: metadata.scope }),\n ...(metadata.contacts !== undefined && { contacts: metadata.contacts }),\n ...(metadata.tos_uri !== undefined && { tos_uri: metadata.tos_uri }),\n ...(metadata.policy_uri !== undefined && { policy_uri: metadata.policy_uri }),\n ...(metadata.jwks_uri !== undefined && { jwks_uri: metadata.jwks_uri }),\n ...(metadata.jwks !== undefined && { jwks: metadata.jwks }),\n ...(metadata.software_id !== undefined && { software_id: metadata.software_id }),\n ...(metadata.software_version !== undefined && { software_version: metadata.software_version }),\n created_at: Date.now(),\n };\n\n // Store client\n await store.set(`dcr:client:${client_id}`, client);\n\n // Return client information (excluding internal created_at)\n const { created_at, ...clientInfo } = client;\n return clientInfo;\n}\n\n/**\n * Get a registered client by ID\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @returns Registered client or undefined if not found\n */\nexport async function getClient(store: Keyv, clientId: string): Promise<RegisteredClient | undefined> {\n return await store.get(`dcr:client:${clientId}`);\n}\n\n/**\n * Validate client credentials\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param clientSecret - Client secret\n * @returns True if credentials are valid\n */\nexport async function validateClient(store: Keyv, clientId: string, clientSecret: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client) return false;\n return client.client_secret === clientSecret;\n}\n\n/**\n * Validate redirect URI for a client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param redirectUri - Redirect URI to validate\n * @returns True if redirect URI is registered\n */\nexport async function validateRedirectUri(store: Keyv, clientId: string, redirectUri: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client || !client.redirect_uris) return false;\n return client.redirect_uris.includes(redirectUri);\n}\n\n/**\n * List all registered clients (for debugging)\n *\n * Note: This method uses Keyv's iterator which may not be available on all storage adapters.\n * For production use, consider maintaining a separate index of client IDs.\n *\n * @param store - Keyv store for all DCR data\n * @returns Array of all registered clients\n */\nexport async function listClients(store: Keyv): Promise<RegisteredClient[]> {\n const clients: RegisteredClient[] = [];\n\n // Check if iterator is available on the store\n if (store.iterator) {\n // Use iterator with namespace to iterate through dcr:client: keys\n const iterator = store.iterator('dcr:client:');\n for await (const [_key, value] of iterator) {\n if (value !== undefined) {\n clients.push(value as RegisteredClient);\n }\n }\n }\n\n return clients;\n}\n\n/**\n * Delete a registered client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n */\nexport async function deleteClient(store: Keyv, clientId: string): Promise<void> {\n await store.delete(`dcr:client:${clientId}`);\n}\n\n// ============================================================================\n// Provider Token Operations\n// ============================================================================\n\n/**\n * Store provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token (used as key)\n * @param tokens - Microsoft provider tokens (access, refresh, expiry)\n */\nexport async function setProviderTokens(store: Keyv, dcrToken: string, tokens: ProviderTokens): Promise<void> {\n await store.set(`dcr:provider:${dcrToken}`, tokens);\n}\n\n/**\n * Retrieve provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n * @returns Provider tokens or undefined if not found\n */\nexport async function getProviderTokens(store: Keyv, dcrToken: string): Promise<ProviderTokens | undefined> {\n return await store.get(`dcr:provider:${dcrToken}`);\n}\n\n/**\n * Delete provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n */\nexport async function deleteProviderTokens(store: Keyv, dcrToken: string): Promise<void> {\n await store.delete(`dcr:provider:${dcrToken}`);\n}\n\n// ============================================================================\n// Authorization Code Operations\n// ============================================================================\n\n/**\n * Store an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @param authCode - Authorization code data\n */\nexport async function setAuthCode(store: Keyv, code: string, authCode: AuthorizationCode): Promise<void> {\n await store.set(`dcr:authcode:${code}`, authCode);\n}\n\n/**\n * Get an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @returns Authorization code data or undefined if not found\n */\nexport async function getAuthCode(store: Keyv, code: string): Promise<AuthorizationCode | undefined> {\n return await store.get(`dcr:authcode:${code}`);\n}\n\n/**\n * Delete an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n */\nexport async function deleteAuthCode(store: Keyv, code: string): Promise<void> {\n await store.delete(`dcr:authcode:${code}`);\n}\n\n// ============================================================================\n// Access Token Operations\n// ============================================================================\n\n/**\n * Store an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @param tokenData - Access token data\n */\nexport async function setAccessToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:access:${token}`, tokenData);\n}\n\n/**\n * Get an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @returns Access token data or undefined if not found\n */\nexport async function getAccessToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:access:${token}`);\n}\n\n/**\n * Delete an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n */\nexport async function deleteAccessToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:access:${token}`);\n}\n\n// ============================================================================\n// Refresh Token Operations\n// ============================================================================\n\n/**\n * Store a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @param tokenData - Access token data (contains refresh token context)\n */\nexport async function setRefreshToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:refresh:${token}`, tokenData);\n}\n\n/**\n * Get a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @returns Access token data or undefined if not found\n */\nexport async function getRefreshToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:refresh:${token}`);\n}\n\n/**\n * Delete a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n */\nexport async function deleteRefreshToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:refresh:${token}`);\n}\n"],"names":["randomUUID","registerClient","store","metadata","redirect_uris","length","Error","client_id","client_secret","grant_types","response_types","client","client_id_issued_at","Math","floor","Date","now","client_secret_expires_at","token_endpoint_auth_method","client_name","undefined","client_uri","logo_uri","scope","contacts","tos_uri","policy_uri","jwks_uri","jwks","software_id","software_version","created_at","set","clientInfo","getClient","clientId","get","validateClient","clientSecret","validateRedirectUri","redirectUri","includes","listClients","clients","iterator","_key","value","push","deleteClient","delete","setProviderTokens","dcrToken","tokens","getProviderTokens","deleteProviderTokens","setAuthCode","code","authCode","getAuthCode","deleteAuthCode","setAccessToken","token","tokenData","getAccessToken","deleteAccessToken","setRefreshToken","getRefreshToken","deleteRefreshToken"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/oauth-microsoft/src/lib/dcr-utils.ts"],"sourcesContent":["/**\n * DCR Storage Utilities\n *\n * Keyv-based storage utilities for Dynamic Client Registration.\n * Follows @mcp-z/oauth pattern: single Keyv store with compound keys.\n *\n * Key Patterns:\n * - dcr:client:{clientId} -> RegisteredClient\n * - dcr:provider:{dcrToken} -> ProviderTokens\n * - dcr:authcode:{code} -> AuthorizationCode\n * - dcr:access:{token} -> AccessToken\n * - dcr:refresh:{token} -> AccessToken\n */\n\nimport type { DcrClientInformation, DcrClientMetadata, ProviderTokens } from '@mcp-z/oauth';\nimport { randomUUID } from 'crypto';\nimport type { Keyv } from 'keyv';\nimport type { AccessToken, AuthorizationCode, RegisteredClient } from '../types.ts';\n\nconst TEN_MINUTES_MS = 10 * 60 * 1000;\nconst ONE_HOUR_MS = 60 * 60 * 1000;\nconst THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;\n\n// ============================================================================\n// Client Operations\n// ============================================================================\n\n/**\n * Register a new OAuth client (RFC 7591 Section 3.1)\n *\n * @param store - Keyv store for all DCR data\n * @param metadata - Client registration metadata\n * @returns Registered client with credentials\n * @throws Error if validation fails\n */\nexport async function registerClient(store: Keyv, metadata: DcrClientMetadata): Promise<DcrClientInformation> {\n // Validate redirect URIs (required per RFC 7591)\n if (!metadata.redirect_uris || metadata.redirect_uris.length === 0) {\n throw new Error('redirect_uris is required');\n }\n\n // Generate client credentials\n const client_id = `dcr_${randomUUID()}`;\n const client_secret = randomUUID();\n\n // Default grant types and response types per RFC 7591 Section 2\n const grant_types = metadata.grant_types ?? ['authorization_code', 'refresh_token'];\n const response_types = metadata.response_types ?? ['code'];\n\n // Build registered client - only include optional fields if they have values\n const client: RegisteredClient = {\n client_id,\n client_secret,\n client_id_issued_at: Math.floor(Date.now() / 1000),\n client_secret_expires_at: 0, // Never expires\n redirect_uris: metadata.redirect_uris,\n token_endpoint_auth_method: metadata.token_endpoint_auth_method ?? 'client_secret_basic',\n grant_types,\n response_types,\n ...(metadata.client_name !== undefined && { client_name: metadata.client_name }),\n ...(metadata.client_uri !== undefined && { client_uri: metadata.client_uri }),\n ...(metadata.logo_uri !== undefined && { logo_uri: metadata.logo_uri }),\n ...(metadata.scope !== undefined && { scope: metadata.scope }),\n ...(metadata.contacts !== undefined && { contacts: metadata.contacts }),\n ...(metadata.tos_uri !== undefined && { tos_uri: metadata.tos_uri }),\n ...(metadata.policy_uri !== undefined && { policy_uri: metadata.policy_uri }),\n ...(metadata.jwks_uri !== undefined && { jwks_uri: metadata.jwks_uri }),\n ...(metadata.jwks !== undefined && { jwks: metadata.jwks }),\n ...(metadata.software_id !== undefined && { software_id: metadata.software_id }),\n ...(metadata.software_version !== undefined && { software_version: metadata.software_version }),\n created_at: Date.now(),\n };\n\n // Store client\n await store.set(`dcr:client:${client_id}`, client);\n\n // Return client information (excluding internal created_at)\n const { created_at, ...clientInfo } = client;\n return clientInfo;\n}\n\n/**\n * Get a registered client by ID\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @returns Registered client or undefined if not found\n */\nexport async function getClient(store: Keyv, clientId: string): Promise<RegisteredClient | undefined> {\n return await store.get(`dcr:client:${clientId}`);\n}\n\n/**\n * Validate client credentials\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param clientSecret - Client secret\n * @returns True if credentials are valid\n */\nexport async function validateClient(store: Keyv, clientId: string, clientSecret: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client) return false;\n return client.client_secret === clientSecret;\n}\n\n/**\n * Validate redirect URI for a client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n * @param redirectUri - Redirect URI to validate\n * @returns True if redirect URI is registered\n */\nexport async function validateRedirectUri(store: Keyv, clientId: string, redirectUri: string): Promise<boolean> {\n const client = await getClient(store, clientId);\n if (!client || !client.redirect_uris) return false;\n return client.redirect_uris.includes(redirectUri);\n}\n\n/**\n * List all registered clients (for debugging)\n *\n * Note: This method uses Keyv's iterator which may not be available on all storage adapters.\n * For production use, consider maintaining a separate index of client IDs.\n *\n * @param store - Keyv store for all DCR data\n * @returns Array of all registered clients\n */\nexport async function listClients(store: Keyv): Promise<RegisteredClient[]> {\n const clients: RegisteredClient[] = [];\n\n // Check if iterator is available on the store\n if (store.iterator) {\n // Use iterator with namespace to iterate through dcr:client: keys\n const iterator = store.iterator('dcr:client:');\n for await (const [_key, value] of iterator) {\n if (value !== undefined) {\n clients.push(value as RegisteredClient);\n }\n }\n }\n\n return clients;\n}\n\n/**\n * Delete a registered client\n *\n * @param store - Keyv store for all DCR data\n * @param clientId - Client identifier\n */\nexport async function deleteClient(store: Keyv, clientId: string): Promise<void> {\n await store.delete(`dcr:client:${clientId}`);\n}\n\n// ============================================================================\n// Provider Token Operations\n// ============================================================================\n\n/**\n * Store provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token (used as key)\n * @param tokens - Microsoft provider tokens (access, refresh, expiry)\n */\nexport async function setProviderTokens(store: Keyv, dcrToken: string, tokens: ProviderTokens): Promise<void> {\n await store.set(`dcr:provider:${dcrToken}`, tokens, ONE_HOUR_MS);\n}\n\n/**\n * Retrieve provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n * @returns Provider tokens or undefined if not found\n */\nexport async function getProviderTokens(store: Keyv, dcrToken: string): Promise<ProviderTokens | undefined> {\n return await store.get(`dcr:provider:${dcrToken}`);\n}\n\n/**\n * Delete provider tokens for a DCR access token\n *\n * @param store - Keyv store for all DCR data\n * @param dcrToken - DCR-issued access token\n */\nexport async function deleteProviderTokens(store: Keyv, dcrToken: string): Promise<void> {\n await store.delete(`dcr:provider:${dcrToken}`);\n}\n\n// ============================================================================\n// Authorization Code Operations\n// ============================================================================\n\n/**\n * Store an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @param authCode - Authorization code data\n */\nexport async function setAuthCode(store: Keyv, code: string, authCode: AuthorizationCode): Promise<void> {\n await store.set(`dcr:authcode:${code}`, authCode, TEN_MINUTES_MS);\n}\n\n/**\n * Get an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n * @returns Authorization code data or undefined if not found\n */\nexport async function getAuthCode(store: Keyv, code: string): Promise<AuthorizationCode | undefined> {\n return await store.get(`dcr:authcode:${code}`);\n}\n\n/**\n * Delete an authorization code\n *\n * @param store - Keyv store for all DCR data\n * @param code - Authorization code\n */\nexport async function deleteAuthCode(store: Keyv, code: string): Promise<void> {\n await store.delete(`dcr:authcode:${code}`);\n}\n\n// ============================================================================\n// Access Token Operations\n// ============================================================================\n\n/**\n * Store an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @param tokenData - Access token data\n */\nexport async function setAccessToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:access:${token}`, tokenData, ONE_HOUR_MS);\n}\n\n/**\n * Get an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n * @returns Access token data or undefined if not found\n */\nexport async function getAccessToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:access:${token}`);\n}\n\n/**\n * Delete an access token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Access token\n */\nexport async function deleteAccessToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:access:${token}`);\n}\n\n// ============================================================================\n// Refresh Token Operations\n// ============================================================================\n\n/**\n * Store a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @param tokenData - Access token data (contains refresh token context)\n */\nexport async function setRefreshToken(store: Keyv, token: string, tokenData: AccessToken): Promise<void> {\n await store.set(`dcr:refresh:${token}`, tokenData, THIRTY_DAYS_MS);\n}\n\n/**\n * Get a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n * @returns Access token data or undefined if not found\n */\nexport async function getRefreshToken(store: Keyv, token: string): Promise<AccessToken | undefined> {\n return await store.get(`dcr:refresh:${token}`);\n}\n\n/**\n * Delete a refresh token\n *\n * @param store - Keyv store for all DCR data\n * @param token - Refresh token\n */\nexport async function deleteRefreshToken(store: Keyv, token: string): Promise<void> {\n await store.delete(`dcr:refresh:${token}`);\n}\n"],"names":["randomUUID","TEN_MINUTES_MS","ONE_HOUR_MS","THIRTY_DAYS_MS","registerClient","store","metadata","redirect_uris","length","Error","client_id","client_secret","grant_types","response_types","client","client_id_issued_at","Math","floor","Date","now","client_secret_expires_at","token_endpoint_auth_method","client_name","undefined","client_uri","logo_uri","scope","contacts","tos_uri","policy_uri","jwks_uri","jwks","software_id","software_version","created_at","set","clientInfo","getClient","clientId","get","validateClient","clientSecret","validateRedirectUri","redirectUri","includes","listClients","clients","iterator","_key","value","push","deleteClient","delete","setProviderTokens","dcrToken","tokens","getProviderTokens","deleteProviderTokens","setAuthCode","code","authCode","getAuthCode","deleteAuthCode","setAccessToken","token","tokenData","getAccessToken","deleteAccessToken","setRefreshToken","getRefreshToken","deleteRefreshToken"],"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.4",
3
+ "version": "1.0.5",
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,31 +52,30 @@
52
52
  "version": "tsds version"
53
53
  },
54
54
  "dependencies": {
55
- "@mcp-z/oauth": "^1.0.1",
56
- "express": "^5.2.1",
55
+ "@mcp-z/oauth": "^1.0.0",
56
+ "express": "^5.0.0",
57
57
  "open": "^11.0.0",
58
- "zod": "^4.3.4"
58
+ "zod": "^4.0.0"
59
59
  },
60
60
  "devDependencies": {
61
- "@mcp-z/client": "^1.0.4",
62
- "@microsoft/microsoft-graph-client": "^3.0.7",
63
- "@modelcontextprotocol/sdk": "^1.25.1",
61
+ "@mcp-z/client": "^1.0.5",
62
+ "@microsoft/microsoft-graph-client": "^3.0.0",
63
+ "@modelcontextprotocol/sdk": "^1.0.0",
64
64
  "@types/cors": "^2.8.19",
65
65
  "@types/express": "^5.0.6",
66
66
  "@types/mocha": "^10.0.10",
67
67
  "@types/node": "^25.0.3",
68
- "cors": "^2.8.5",
68
+ "cors": "^2.0.0",
69
69
  "dotenv": "^17.2.3",
70
70
  "get-port": "^7.1.0",
71
- "keyv": "^5.5.5",
72
- "keyv-file": "^5.3.3",
71
+ "keyv": "^5.0.0",
72
+ "keyv-file": "^5.0.0",
73
73
  "node-version-use": "^2.4.7",
74
74
  "ts-dev-stack": "^1.22.1",
75
- "tsds-config": "^1.0.4",
76
- "typescript": "^5.9.3"
75
+ "tsds-config": "^1.0.4"
77
76
  },
78
77
  "peerDependencies": {
79
- "keyv": "^5.5.5"
78
+ "keyv": "^5.0.0"
80
79
  },
81
80
  "engines": {
82
81
  "node": ">=24"