Skip to main content
Glama
keychain.ts6.34 kB
import keytar from 'keytar'; import { log } from './logger.js'; /** * Service name used for keychain operations */ export const KEYCHAIN_SERVICE_NAME = 'auth0-mcp'; /** * Keychain item keys for Auth0 related tokens and configuration * @readonly * @enum {string} */ export const KeychainItem = { /** Access token for Auth0 Management API */ TOKEN: 'AUTH0_TOKEN', /** Auth0 tenant domain */ DOMAIN: 'AUTH0_DOMAIN', /** OAuth refresh token for obtaining new access tokens */ REFRESH_TOKEN: 'AUTH0_REFRESH_TOKEN', /** Timestamp when the current token expires */ TOKEN_EXPIRES_AT: 'AUTH0_TOKEN_EXPIRES_AT', } as const; /** * Array of all keychain item keys for operations that need to process all items * @type {string[]} */ export const ALL_KEYCHAIN_ITEMS = Object.values(KeychainItem); /** * Type representing the result of a keychain operation */ export type KeychainOperationResult = { item: string; success: boolean; error?: Error; }; /** * Keychain service for securely storing Auth0 credentials * Provides type-safe methods for working with Auth0 tokens and settings */ class KeychainService { private serviceName: string; /** * Creates a new KeychainService instance * @param serviceName - The keychain service name to use */ constructor(serviceName: string = KEYCHAIN_SERVICE_NAME) { this.serviceName = serviceName; } /** * Store the Auth0 access token in the keychain * @param token - The access token to store * @returns A promise that resolves to true if successful, false otherwise */ async setToken(token: string): Promise<boolean> { return this.set(KeychainItem.TOKEN, token); } /** * Retrieve the Auth0 access token from the keychain * @returns A promise that resolves to the access token or null if not found */ async getToken(): Promise<string | null> { return this.get(KeychainItem.TOKEN); } /** * Store the Auth0 domain in the keychain * @param domain - The domain to store * @returns A promise that resolves to true if successful, false otherwise */ async setDomain(domain: string): Promise<boolean> { return this.set(KeychainItem.DOMAIN, domain); } /** * Retrieve the Auth0 domain from the keychain * @returns A promise that resolves to the domain or null if not found */ async getDomain(): Promise<string | null> { return this.get(KeychainItem.DOMAIN); } /** * Store the Auth0 refresh token in the keychain * @param refreshToken - The refresh token to store * @returns A promise that resolves to true if successful, false otherwise */ async setRefreshToken(refreshToken: string): Promise<boolean> { return this.set(KeychainItem.REFRESH_TOKEN, refreshToken); } /** * Retrieve the Auth0 refresh token from the keychain * @returns A promise that resolves to the refresh token or null if not found */ async getRefreshToken(): Promise<string | null> { return this.get(KeychainItem.REFRESH_TOKEN); } /** * Store the token expiration timestamp in the keychain * @param timestamp - The expiration timestamp in milliseconds since epoch * @returns A promise that resolves to true if successful, false otherwise */ async setTokenExpiresAt(timestamp: number): Promise<boolean> { return this.set(KeychainItem.TOKEN_EXPIRES_AT, timestamp.toString()); } /** * Retrieve the token expiration timestamp from the keychain * @returns A promise that resolves to the timestamp as a number or null if not found */ async getTokenExpiresAt(): Promise<number | null> { const value = await this.get(KeychainItem.TOKEN_EXPIRES_AT); return value ? parseInt(value, 10) : null; } /** * Delete all Auth0 related items from the keychain * @returns A promise that resolves to an array of results for each deletion operation */ async clearAll(): Promise<KeychainOperationResult[]> { const results = await Promise.all( ALL_KEYCHAIN_ITEMS.map(async (item) => { try { const result = await keytar.deletePassword(this.serviceName, item); log(`Deleted ${item} from keychain: ${result ? 'Success' : 'Not found'}`); return { item, success: result }; } catch (error) { log(`Error deleting ${item} from keychain:`, error); if (error instanceof Error) { return { item, success: false, error }; } return { item, success: false, error: new Error(String(error)) }; } }) ); // Log a summary of the results const successCount = results.filter((r) => r.success).length; log(`Cleared ${successCount}/${ALL_KEYCHAIN_ITEMS.length} items from keychain`); return results; } /** * Delete a specific item from the keychain * @param key - The key to delete * @returns A promise that resolves to true if successful, false otherwise */ async delete(key: string): Promise<boolean> { try { const result = await keytar.deletePassword(this.serviceName, key); log(`Deleted ${key} from keychain: ${result ? 'Success' : 'Not found'}`); return result; } catch (error) { log(`Error deleting ${key} from keychain:`, error); return false; } } /** * Internal method to store a value in the system keychain * @param key - The key to store the value under * @param value - The value to store * @returns A promise that resolves to true if successful, false otherwise * @private */ private async set(key: string, value: string): Promise<boolean> { try { await keytar.setPassword(this.serviceName, key, value); log(`Successfully stored ${key} in keychain`); return true; } catch (error) { log(`Error storing ${key} in keychain:`, error); return false; } } /** * Internal method to retrieve a value from the system keychain * @param key - The key to retrieve * @returns A promise that resolves to the stored value or null if not found * @private */ private async get(key: string): Promise<string | null> { try { return await keytar.getPassword(this.serviceName, key); } catch (error) { log(`Error retrieving ${key} from keychain:`, error); return null; } } } export const keychain = new KeychainService(KEYCHAIN_SERVICE_NAME);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/auth0/auth0-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server