UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

399 lines 15.1 kB
// src/cli/commands/authProviders.ts /** * Multi-provider authentication CLI handlers. * * Provides commands for listing, validating, and health-checking * authentication providers (Auth0, Clerk, Firebase, Supabase, etc.). */ import chalk from "chalk"; import { AuthProviderFactory } from "../../lib/auth/AuthProviderFactory.js"; import { logger } from "../../lib/utils/logger.js"; /** * Provider information for display */ const PROVIDER_INFO = { auth0: { name: "Auth0", description: "Enterprise identity platform with JWT and session support", requiredConfig: ["domain", "clientId"], website: "https://auth0.com", }, clerk: { name: "Clerk", description: "Modern authentication with session-based and JWT support", requiredConfig: ["publishableKey", "secretKey"], website: "https://clerk.com", }, supabase: { name: "Supabase Auth", description: "Open-source Firebase alternative with JWT authentication", requiredConfig: ["url", "anonKey"], website: "https://supabase.com", }, firebase: { name: "Firebase Auth", description: "Google's authentication service with multiple providers", requiredConfig: ["projectId"], website: "https://firebase.google.com", }, workos: { name: "WorkOS", description: "Enterprise-ready authentication with SSO support", requiredConfig: ["apiKey", "clientId"], website: "https://workos.com", }, "better-auth": { name: "Better Auth", description: "Self-hosted authentication solution", requiredConfig: ["secret", "baseUrl"], website: "https://github.com/better-auth/better-auth", }, custom: { name: "Custom", description: "Custom authentication adapter for any provider", requiredConfig: ["validateToken"], website: "", }, oauth2: { name: "OAuth2", description: "Generic OAuth2 authentication with configurable endpoints", requiredConfig: [ "clientId", "clientSecret", "authorizationUrl", "tokenUrl", ], website: "https://oauth.net/2/", }, cognito: { name: "AWS Cognito", description: "AWS Cognito user pools with JWT authentication", requiredConfig: ["userPoolId", "clientId", "region"], website: "https://aws.amazon.com/cognito/", }, keycloak: { name: "Keycloak", description: "Open-source identity and access management", requiredConfig: ["realm", "serverUrl", "clientId"], website: "https://www.keycloak.org/", }, jwt: { name: "JWT", description: "Generic JWT token validation with configurable secret/keys", requiredConfig: ["secret"], website: "https://jwt.io/", }, }; /** * Handle 'auth providers' command */ export async function handleProvidersCommand(argv) { const providers = Object.entries(PROVIDER_INFO).filter(([key]) => key !== "custom"); if (argv.format === "json") { const output = providers.map(([type, info]) => ({ type, ...info, })); logger.always(JSON.stringify(output, null, 2)); return; } if (argv.format === "table") { logger.always(chalk.bold("\nAvailable Authentication Providers\n")); logger.always(chalk.gray("+-----------------+--------------------------------------------------+")); logger.always(chalk.gray("| ") + chalk.bold("Provider".padEnd(15)) + chalk.gray(" | ") + chalk.bold("Description".padEnd(48)) + chalk.gray(" |")); logger.always(chalk.gray("+-----------------+--------------------------------------------------+")); for (const [type, info] of providers) { logger.always(chalk.gray("| ") + chalk.cyan(type.padEnd(15)) + chalk.gray(" | ") + info.description.substring(0, 48).padEnd(48) + chalk.gray(" |")); } logger.always(chalk.gray("+-----------------+--------------------------------------------------+")); return; } // Text format (default) logger.always(chalk.bold("\nAvailable Authentication Providers\n")); for (const [type, info] of providers) { logger.always(chalk.cyan.bold(` ${info.name} (${type})`)); logger.always(chalk.gray(` ${info.description}`)); logger.always(chalk.gray(` Required config: ${info.requiredConfig.join(", ")}`)); if (info.website) { logger.always(chalk.gray(` Website: ${info.website}`)); } logger.always(""); } logger.always(chalk.gray("Use 'neurolink auth validate <token> --provider <type>' to validate a token")); logger.always(chalk.gray("Use 'neurolink auth health --provider <type>' to check provider health\n")); } /** * Handle 'auth validate' command */ export async function handleValidateCommand(argv) { try { const providerConfig = buildProviderConfig(argv); if (!providerConfig) { logger.error(chalk.red(`\nError: Missing required configuration for ${argv.provider} provider.\n`)); logger.always(chalk.gray(`Required: ${PROVIDER_INFO[argv.provider].requiredConfig.join(", ")}`)); logger.always(chalk.gray("\nProvide via CLI options or environment variables (e.g., AUTH0_DOMAIN)")); process.exit(1); } const provider = await AuthProviderFactory.createProvider(argv.provider, providerConfig); const result = await provider.authenticateToken(argv.token); if (argv.format === "json") { logger.always(JSON.stringify(result, null, 2)); return; } logger.always(""); if (result.valid) { logger.always(chalk.green.bold("Token is VALID")); logger.always(""); if (result.user) { logger.always(chalk.bold("User Information:")); logger.always(chalk.gray(` ID: ${result.user.id}`)); if (result.user.email) { logger.always(chalk.gray(` Email: ${result.user.email}`)); } if (result.user.name) { logger.always(chalk.gray(` Name: ${result.user.name}`)); } if (result.user.roles.length > 0) { logger.always(chalk.gray(` Roles: ${result.user.roles.join(", ")}`)); } if (result.user.permissions.length > 0) { logger.always(chalk.gray(` Permissions: ${result.user.permissions.join(", ")}`)); } } if (result.expiresAt) { logger.always(""); logger.always(chalk.gray(`Expires: ${result.expiresAt.toISOString()}`)); } if (result.tokenType) { logger.always(chalk.gray(`Token Type: ${result.tokenType}`)); } } else { logger.always(chalk.red.bold("Token is INVALID")); if (result.error) { logger.always(chalk.red(`\nError: ${result.error}`)); } process.exit(1); } logger.always(""); } catch (error) { const message = error instanceof Error ? error.message : String(error); logger.error("Token validation failed:", error); if (argv.format === "json") { logger.always(JSON.stringify({ valid: false, error: message }, null, 2)); } else { logger.error(chalk.red(`\nValidation Error: ${message}\n`)); } process.exit(1); } } /** * Handle 'auth health' command */ export async function handleHealthCommand(argv) { try { const providerConfig = buildProviderConfig(argv); if (!providerConfig) { logger.error(chalk.red(`\nError: Missing required configuration for ${argv.provider} provider.\n`)); logger.always(chalk.gray(`Required: ${PROVIDER_INFO[argv.provider].requiredConfig.join(", ")}`)); logger.always(chalk.gray("\nProvide via CLI options or environment variables (e.g., AUTH0_DOMAIN)")); process.exit(1); } const provider = await AuthProviderFactory.createProvider(argv.provider, providerConfig); const health = await provider.healthCheck?.(); if (!health) { logger.error(chalk.red(`\nProvider ${argv.provider} does not support health checks.\n`)); process.exit(1); } if (argv.format === "json") { logger.always(JSON.stringify(health, null, 2)); return; } logger.always(""); logger.always(chalk.bold(`Auth Provider Health: ${argv.provider}`)); logger.always(""); const statusIcon = health.healthy ? chalk.green("OK") : chalk.red("FAIL"); logger.always(` Overall Status: ${statusIcon}`); logger.always(` Provider Connected: ${health.providerConnected ? chalk.green("Yes") : chalk.red("No")}`); logger.always(` Session Storage: ${health.sessionStorageHealthy ? chalk.green("Healthy") : chalk.red("Unhealthy")}`); if (health.lastSuccessfulAuth) { logger.always(chalk.gray(` Last Auth: ${health.lastSuccessfulAuth.toISOString()}`)); } if (health.error) { logger.always(chalk.red(`\n Error: ${health.error}`)); } logger.always(""); if (!health.healthy) { process.exit(1); } } catch (error) { const message = error instanceof Error ? error.message : String(error); logger.error("Health check failed:", error); if (argv.format === "json") { logger.always(JSON.stringify({ healthy: false, error: message }, null, 2)); } else { logger.error(chalk.red(`\nHealth Check Error: ${message}\n`)); } process.exit(1); } } /** * Build provider configuration from CLI args and environment variables */ function buildProviderConfig(argv) { switch (argv.provider) { case "auth0": { const domain = argv.domain || process.env.AUTH0_DOMAIN; const clientId = argv.clientId || process.env.AUTH0_CLIENT_ID; if (!domain || !clientId) { return null; } return { type: argv.provider, domain, clientId, audience: process.env.AUTH0_AUDIENCE, }; } case "clerk": { const secretKey = argv.secretKey || process.env.CLERK_SECRET_KEY; const publishableKey = process.env.CLERK_PUBLISHABLE_KEY || ""; if (!secretKey) { return null; } return { type: argv.provider, publishableKey, secretKey, }; } case "supabase": { const url = argv.url || process.env.SUPABASE_URL; const anonKey = argv.anonKey || process.env.SUPABASE_ANON_KEY; if (!url || !anonKey) { return null; } return { type: argv.provider, url, anonKey, jwtSecret: process.env.SUPABASE_JWT_SECRET, }; } case "firebase": { const projectId = process.env.FIREBASE_PROJECT_ID; if (!projectId) { return null; } return { type: argv.provider, projectId, apiKey: process.env.FIREBASE_API_KEY, }; } case "workos": { const apiKey = argv.apiKey || process.env.WORKOS_API_KEY; const clientId = argv.clientId || process.env.WORKOS_CLIENT_ID; if (!apiKey || !clientId) { return null; } return { type: argv.provider, apiKey, clientId, }; } case "better-auth": { const secret = argv.secret || process.env.BETTER_AUTH_SECRET; const baseUrl = argv.url || process.env.BETTER_AUTH_BASE_URL; if (!secret || !baseUrl) { return null; } return { type: argv.provider, secret, baseUrl, }; } case "oauth2": { const clientId = argv.clientId || process.env.OAUTH2_CLIENT_ID; const clientSecret = process.env.OAUTH2_CLIENT_SECRET; const authorizationUrl = process.env.OAUTH2_AUTHORIZATION_URL; const tokenUrl = process.env.OAUTH2_TOKEN_URL; if (!clientId || !authorizationUrl || !tokenUrl) { return null; } return { type: argv.provider, clientId, clientSecret, authorizationUrl, tokenUrl, userInfoUrl: process.env.OAUTH2_USERINFO_URL, jwksUrl: process.env.OAUTH2_JWKS_URL, }; } case "cognito": { const userPoolId = process.env.COGNITO_USER_POOL_ID; const clientId = argv.clientId || process.env.COGNITO_CLIENT_ID; const region = process.env.COGNITO_REGION || process.env.AWS_REGION; if (!userPoolId || !clientId || !region) { return null; } return { type: argv.provider, userPoolId, clientId, region, }; } case "keycloak": { const realm = process.env.KEYCLOAK_REALM; const serverUrl = argv.url || process.env.KEYCLOAK_SERVER_URL; const clientId = argv.clientId || process.env.KEYCLOAK_CLIENT_ID; if (!realm || !serverUrl || !clientId) { return null; } return { type: argv.provider, realm, serverUrl, clientId, }; } case "jwt": { const secret = argv.secret || process.env.JWT_SECRET; const publicKey = process.env.JWT_PUBLIC_KEY; if (!secret && !publicKey) { return null; } return { type: argv.provider, secret, publicKey, issuer: process.env.JWT_ISSUER, audience: process.env.JWT_AUDIENCE, }; } case "custom": { // Custom provider requires a validateToken function which can't be // provided via CLI flags. Return null to show guidance message. return null; } default: return null; } } //# sourceMappingURL=authProviders.js.map