diff --git a/apps/sim/app/api/auth/sso/providers/route.ts b/apps/sim/app/api/auth/sso/providers/route.ts index f35f25ee2a..d4bcfa35db 100644 --- a/apps/sim/app/api/auth/sso/providers/route.ts +++ b/apps/sim/app/api/auth/sso/providers/route.ts @@ -4,7 +4,7 @@ import { eq } from 'drizzle-orm' import { NextResponse } from 'next/server' import { getSession } from '@/lib/auth' -const logger = createLogger('SSO-Providers') +const logger = createLogger('SSOProvidersRoute') export async function GET() { try { diff --git a/apps/sim/app/api/auth/sso/register/route.ts b/apps/sim/app/api/auth/sso/register/route.ts index b53d83eae6..00e499d6fb 100644 --- a/apps/sim/app/api/auth/sso/register/route.ts +++ b/apps/sim/app/api/auth/sso/register/route.ts @@ -6,7 +6,7 @@ import { hasSSOAccess } from '@/lib/billing' import { env } from '@/lib/core/config/env' import { REDACTED_MARKER } from '@/lib/core/security/redaction' -const logger = createLogger('SSO-Register') +const logger = createLogger('SSORegisterRoute') const mappingSchema = z .object({ @@ -43,6 +43,10 @@ const ssoRegistrationSchema = z.discriminatedUnion('providerType', [ ]) .default(['openid', 'profile', 'email']), pkce: z.boolean().default(true), + authorizationEndpoint: z.string().url().optional(), + tokenEndpoint: z.string().url().optional(), + userInfoEndpoint: z.string().url().optional(), + jwksEndpoint: z.string().url().optional(), }), z.object({ providerType: z.literal('saml'), @@ -64,12 +68,10 @@ const ssoRegistrationSchema = z.discriminatedUnion('providerType', [ export async function POST(request: NextRequest) { try { - // SSO plugin must be enabled in Better Auth if (!env.SSO_ENABLED) { return NextResponse.json({ error: 'SSO is not enabled' }, { status: 400 }) } - // Check plan access (enterprise) or env var override const session = await getSession() if (!session?.user?.id) { return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) @@ -116,7 +118,16 @@ export async function POST(request: NextRequest) { } if (providerType === 'oidc') { - const { clientId, clientSecret, scopes, pkce } = body + const { + clientId, + clientSecret, + scopes, + pkce, + authorizationEndpoint, + tokenEndpoint, + userInfoEndpoint, + jwksEndpoint, + } = body const oidcConfig: any = { clientId, @@ -127,48 +138,102 @@ export async function POST(request: NextRequest) { pkce: pkce ?? true, } - // Add manual endpoints for providers that might need them - // Common patterns for OIDC providers that don't support discovery properly + oidcConfig.authorizationEndpoint = authorizationEndpoint + oidcConfig.tokenEndpoint = tokenEndpoint + oidcConfig.userInfoEndpoint = userInfoEndpoint + oidcConfig.jwksEndpoint = jwksEndpoint + + const needsDiscovery = + !oidcConfig.authorizationEndpoint || !oidcConfig.tokenEndpoint || !oidcConfig.jwksEndpoint + + if (needsDiscovery) { + const discoveryUrl = `${issuer.replace(/\/$/, '')}/.well-known/openid-configuration` + try { + logger.info('Fetching OIDC discovery document for missing endpoints', { + discoveryUrl, + hasAuthEndpoint: !!oidcConfig.authorizationEndpoint, + hasTokenEndpoint: !!oidcConfig.tokenEndpoint, + hasJwksEndpoint: !!oidcConfig.jwksEndpoint, + }) + + const discoveryResponse = await fetch(discoveryUrl, { + headers: { Accept: 'application/json' }, + }) + + if (!discoveryResponse.ok) { + logger.error('Failed to fetch OIDC discovery document', { + status: discoveryResponse.status, + statusText: discoveryResponse.statusText, + }) + return NextResponse.json( + { + error: `Failed to fetch OIDC discovery document from ${discoveryUrl}. Status: ${discoveryResponse.status}. Provide all endpoints explicitly or verify the issuer URL.`, + }, + { status: 400 } + ) + } + + const discovery = await discoveryResponse.json() + + oidcConfig.authorizationEndpoint = + oidcConfig.authorizationEndpoint || discovery.authorization_endpoint + oidcConfig.tokenEndpoint = oidcConfig.tokenEndpoint || discovery.token_endpoint + oidcConfig.userInfoEndpoint = oidcConfig.userInfoEndpoint || discovery.userinfo_endpoint + oidcConfig.jwksEndpoint = oidcConfig.jwksEndpoint || discovery.jwks_uri + + logger.info('Merged OIDC endpoints (user-provided + discovery)', { + providerId, + issuer, + authorizationEndpoint: oidcConfig.authorizationEndpoint, + tokenEndpoint: oidcConfig.tokenEndpoint, + userInfoEndpoint: oidcConfig.userInfoEndpoint, + jwksEndpoint: oidcConfig.jwksEndpoint, + }) + } catch (error) { + logger.error('Error fetching OIDC discovery document', { + error: error instanceof Error ? error.message : 'Unknown error', + discoveryUrl, + }) + return NextResponse.json( + { + error: `Failed to fetch OIDC discovery document from ${discoveryUrl}. Please verify the issuer URL is correct or provide all endpoints explicitly.`, + }, + { status: 400 } + ) + } + } else { + logger.info('Using explicitly provided OIDC endpoints (all present)', { + providerId, + issuer, + authorizationEndpoint: oidcConfig.authorizationEndpoint, + tokenEndpoint: oidcConfig.tokenEndpoint, + userInfoEndpoint: oidcConfig.userInfoEndpoint, + jwksEndpoint: oidcConfig.jwksEndpoint, + }) + } + if ( - issuer.includes('okta.com') || - issuer.includes('auth0.com') || - issuer.includes('identityserver') + !oidcConfig.authorizationEndpoint || + !oidcConfig.tokenEndpoint || + !oidcConfig.jwksEndpoint ) { - const baseUrl = issuer.includes('/oauth2/default') - ? issuer.replace('/oauth2/default', '') - : issuer.replace('/oauth', '').replace('/v2.0', '').replace('/oauth2', '') - - // Okta-style endpoints - if (issuer.includes('okta.com')) { - oidcConfig.authorizationEndpoint = `${baseUrl}/oauth2/default/v1/authorize` - oidcConfig.tokenEndpoint = `${baseUrl}/oauth2/default/v1/token` - oidcConfig.userInfoEndpoint = `${baseUrl}/oauth2/default/v1/userinfo` - oidcConfig.jwksEndpoint = `${baseUrl}/oauth2/default/v1/keys` - } - // Auth0-style endpoints - else if (issuer.includes('auth0.com')) { - oidcConfig.authorizationEndpoint = `${baseUrl}/authorize` - oidcConfig.tokenEndpoint = `${baseUrl}/oauth/token` - oidcConfig.userInfoEndpoint = `${baseUrl}/userinfo` - oidcConfig.jwksEndpoint = `${baseUrl}/.well-known/jwks.json` - } - // Generic OIDC endpoints (IdentityServer, etc.) - else { - oidcConfig.authorizationEndpoint = `${baseUrl}/connect/authorize` - oidcConfig.tokenEndpoint = `${baseUrl}/connect/token` - oidcConfig.userInfoEndpoint = `${baseUrl}/connect/userinfo` - oidcConfig.jwksEndpoint = `${baseUrl}/.well-known/jwks` - } + const missing: string[] = [] + if (!oidcConfig.authorizationEndpoint) missing.push('authorizationEndpoint') + if (!oidcConfig.tokenEndpoint) missing.push('tokenEndpoint') + if (!oidcConfig.jwksEndpoint) missing.push('jwksEndpoint') - logger.info('Using manual OIDC endpoints for provider', { - providerId, - provider: issuer.includes('okta.com') - ? 'Okta' - : issuer.includes('auth0.com') - ? 'Auth0' - : 'Generic', - authEndpoint: oidcConfig.authorizationEndpoint, + logger.error('Missing required OIDC endpoints after discovery merge', { + missing, + authorizationEndpoint: oidcConfig.authorizationEndpoint, + tokenEndpoint: oidcConfig.tokenEndpoint, + jwksEndpoint: oidcConfig.jwksEndpoint, }) + return NextResponse.json( + { + error: `Missing required OIDC endpoints: ${missing.join(', ')}. Please provide these explicitly or verify the issuer supports OIDC discovery.`, + }, + { status: 400 } + ) } providerConfig.oidcConfig = oidcConfig diff --git a/apps/sim/lib/copilot/tools/client/workflow/deploy-api.ts b/apps/sim/lib/copilot/tools/client/workflow/deploy-api.ts index 49abe62911..c850dd4933 100644 --- a/apps/sim/lib/copilot/tools/client/workflow/deploy-api.ts +++ b/apps/sim/lib/copilot/tools/client/workflow/deploy-api.ts @@ -6,6 +6,7 @@ import { ClientToolCallState, } from '@/lib/copilot/tools/client/base-tool' import { registerToolUIConfig } from '@/lib/copilot/tools/client/ui-config' +import { getBaseUrl } from '@/lib/core/utils/urls' import { getInputFormatExample } from '@/lib/workflows/operations/deployment-utils' import { useCopilotStore } from '@/stores/panel/copilot/store' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' @@ -36,7 +37,6 @@ export class DeployApiClientTool extends BaseClientTool { const action = params?.action || 'deploy' - // Check if workflow is already deployed const workflowId = params?.workflowId || useWorkflowRegistry.getState().activeWorkflowId const isAlreadyDeployed = workflowId ? useWorkflowRegistry.getState().getWorkflowDeploymentStatus(workflowId)?.isDeployed @@ -89,7 +89,6 @@ export class DeployApiClientTool extends BaseClientTool { getDynamicText: (params, state) => { const action = params?.action === 'undeploy' ? 'undeploy' : 'deploy' - // Check if workflow is already deployed const workflowId = params?.workflowId || useWorkflowRegistry.getState().activeWorkflowId const isAlreadyDeployed = workflowId ? useWorkflowRegistry.getState().getWorkflowDeploymentStatus(workflowId)?.isDeployed @@ -231,10 +230,7 @@ export class DeployApiClientTool extends BaseClientTool { } if (action === 'deploy') { - const appUrl = - typeof window !== 'undefined' - ? window.location.origin - : process.env.NEXT_PUBLIC_APP_URL || 'https://app.sim.ai' + const appUrl = getBaseUrl() const apiEndpoint = `${appUrl}/api/workflows/${workflowId}/execute` const apiKeyPlaceholder = '$SIM_API_KEY' diff --git a/apps/sim/tools/http/utils.ts b/apps/sim/tools/http/utils.ts index 876cc91da5..c21f30623a 100644 --- a/apps/sim/tools/http/utils.ts +++ b/apps/sim/tools/http/utils.ts @@ -1,11 +1,7 @@ -import { createLogger } from '@sim/logger' -import { isTest } from '@/lib/core/config/feature-flags' import { getBaseUrl } from '@/lib/core/utils/urls' import { transformTable } from '@/tools/shared/table' import type { TableRow } from '@/tools/types' -const logger = createLogger('HTTPRequestUtils') - /** * Creates a set of default headers used in HTTP requests * @param customHeaders Additional user-provided headers to include @@ -30,7 +26,6 @@ export const getDefaultHeaders = ( ...customHeaders, } - // Add Host header if not provided and URL is valid if (url) { try { const hostname = new URL(url).host @@ -57,26 +52,21 @@ export const processUrl = ( pathParams?: Record, queryParams?: TableRow[] | null ): string => { - // Strip any surrounding quotes if ((url.startsWith('"') && url.endsWith('"')) || (url.startsWith("'") && url.endsWith("'"))) { url = url.slice(1, -1) } - // Replace path parameters if (pathParams) { Object.entries(pathParams).forEach(([key, value]) => { url = url.replace(`:${key}`, encodeURIComponent(value)) }) } - // Handle query parameters if (queryParams) { const queryParamsObj = transformTable(queryParams) - // Verify if URL already has query params to use proper separator const separator = url.includes('?') ? '&' : '?' - // Build query string manually to avoid double-encoding issues const queryParts: string[] = [] for (const [key, value] of Object.entries(queryParamsObj)) { @@ -92,31 +82,3 @@ export const processUrl = ( return url } - -// Check if a URL needs proxy to avoid CORS/method restrictions -export const shouldUseProxy = (url: string): boolean => { - // Skip proxying in test environment - if (isTest) { - return false - } - - // Only consider proxying in browser environment - if (typeof window === 'undefined') { - return false - } - - try { - const _urlObj = new URL(url) - const currentOrigin = window.location.origin - - // Don't proxy same-origin or localhost requests - if (url.startsWith(currentOrigin) || url.includes('localhost')) { - return false - } - - return true // Proxy all cross-origin requests for consistency - } catch (e) { - logger.warn('URL parsing failed:', e) - return false - } -} diff --git a/packages/db/scripts/deregister-sso-provider.ts b/packages/db/scripts/deregister-sso-provider.ts index f22c317e19..a079746d84 100644 --- a/packages/db/scripts/deregister-sso-provider.ts +++ b/packages/db/scripts/deregister-sso-provider.ts @@ -18,7 +18,6 @@ import { drizzle } from 'drizzle-orm/postgres-js' import postgres from 'postgres' import { ssoProvider, user } from '../schema' -// Simple console logger const logger = { info: (message: string, meta?: any) => { const timestamp = new Date().toISOString() @@ -43,7 +42,6 @@ const logger = { }, } -// Get database URL from environment const CONNECTION_STRING = process.env.POSTGRES_URL ?? process.env.DATABASE_URL if (!CONNECTION_STRING) { console.error('❌ POSTGRES_URL or DATABASE_URL environment variable is required') @@ -88,7 +86,6 @@ async function deregisterSSOProvider(): Promise { return false } - // Get user const targetUser = await getUser(userEmail) if (!targetUser) { return false @@ -96,7 +93,6 @@ async function deregisterSSOProvider(): Promise { logger.info(`Found user: ${targetUser.email} (ID: ${targetUser.id})`) - // Get SSO providers for this user const providers = await db .select() .from(ssoProvider) @@ -112,11 +108,9 @@ async function deregisterSSOProvider(): Promise { logger.info(` - Provider ID: ${provider.providerId}, Domain: ${provider.domain}`) } - // Check if specific provider ID was requested const specificProviderId = process.env.SSO_PROVIDER_ID if (specificProviderId) { - // Delete specific provider const providerToDelete = providers.find((p) => p.providerId === specificProviderId) if (!providerToDelete) { logger.error(`Provider '${specificProviderId}' not found for user ${targetUser.email}`) @@ -133,7 +127,6 @@ async function deregisterSSOProvider(): Promise { `✅ Successfully deleted SSO provider '${specificProviderId}' for user ${targetUser.email}` ) } else { - // Delete all providers for this user await db.delete(ssoProvider).where(eq(ssoProvider.userId, targetUser.id)) logger.info( @@ -171,7 +164,6 @@ async function main() { } } -// Handle script execution main().catch((error) => { logger.error('Script execution failed:', { error }) process.exit(1) diff --git a/packages/db/scripts/register-sso-provider.ts b/packages/db/scripts/register-sso-provider.ts index 9b29acc67d..07d0ff7684 100644 --- a/packages/db/scripts/register-sso-provider.ts +++ b/packages/db/scripts/register-sso-provider.ts @@ -38,7 +38,6 @@ import postgres from 'postgres' import { v4 as uuidv4 } from 'uuid' import { ssoProvider, user } from '../schema' -// Self-contained SSO types (matching Better Auth's structure) interface SSOMapping { id: string email: string @@ -108,7 +107,6 @@ interface SSOProviderConfig { samlConfig?: SAMLConfig } -// Simple console logger (no dependencies) const logger = { info: (message: string, meta?: any) => { const timestamp = new Date().toISOString() @@ -133,14 +131,12 @@ const logger = { }, } -// Get database URL from environment const CONNECTION_STRING = process.env.POSTGRES_URL ?? process.env.DATABASE_URL if (!CONNECTION_STRING) { console.error('❌ POSTGRES_URL or DATABASE_URL environment variable is required') process.exit(1) } -// Initialize database connection (following migration script pattern) const postgresClient = postgres(CONNECTION_STRING, { prepare: false, idle_timeout: 20, @@ -161,7 +157,6 @@ interface SSOProviderData { organizationId?: string } -// Self-contained configuration builder (no external dependencies) function buildSSOConfigFromEnv(): SSOProviderConfig | null { const enabled = process.env.SSO_ENABLED === 'true' if (!enabled) return null @@ -182,7 +177,6 @@ function buildSSOConfigFromEnv(): SSOProviderConfig | null { providerType, } - // Build field mapping config.mapping = { id: process.env.SSO_MAPPING_ID || @@ -202,7 +196,6 @@ function buildSSOConfigFromEnv(): SSOProviderConfig | null { image: process.env.SSO_MAPPING_IMAGE || (providerType === 'oidc' ? 'picture' : undefined), } - // Build provider-specific configuration if (providerType === 'oidc') { const clientId = process.env.SSO_OIDC_CLIENT_ID const clientSecret = process.env.SSO_OIDC_CLIENT_SECRET @@ -225,7 +218,8 @@ function buildSSOConfigFromEnv(): SSOProviderConfig | null { userInfoEndpoint: process.env.SSO_OIDC_USERINFO_ENDPOINT, jwksEndpoint: process.env.SSO_OIDC_JWKS_ENDPOINT, discoveryEndpoint: - process.env.SSO_OIDC_DISCOVERY_ENDPOINT || `${issuer}/.well-known/openid-configuration`, + process.env.SSO_OIDC_DISCOVERY_ENDPOINT || + `${issuer.replace(/\/$/, '')}/.well-known/openid-configuration`, } } else if (providerType === 'saml') { const entryPoint = process.env.SSO_SAML_ENTRY_POINT @@ -237,7 +231,6 @@ function buildSSOConfigFromEnv(): SSOProviderConfig | null { const callbackUrl = process.env.SSO_SAML_CALLBACK_URL || `${issuer}/callback` - // Use custom metadata if provided, otherwise generate default let spMetadata = process.env.SSO_SAML_SP_METADATA if (!spMetadata) { spMetadata = ` @@ -263,7 +256,6 @@ function buildSSOConfigFromEnv(): SSOProviderConfig | null { entityID: issuer, }, } - // Optionally include IDP metadata if provided const idpMetadata = process.env.SSO_SAML_IDP_METADATA if (idpMetadata) { config.samlConfig.idpMetadata = { @@ -275,7 +267,6 @@ function buildSSOConfigFromEnv(): SSOProviderConfig | null { return config } -// Self-contained example environment variables function function getExampleEnvVars( providerType: 'oidc' | 'saml', provider?: string @@ -358,7 +349,6 @@ async function getAdminUser(): Promise<{ id: string; email: string } | null> { async function registerSSOProvider(): Promise { try { - // Build configuration from environment variables const ssoConfig = buildSSOConfigFromEnv() if (!ssoConfig) { @@ -381,7 +371,6 @@ async function registerSSOProvider(): Promise { return false } - // Get admin user const adminUser = await getAdminUser() if (!adminUser) { return false @@ -394,7 +383,6 @@ async function registerSSOProvider(): Promise { adminUser: adminUser.email, }) - // Validate issuer URL (same as Better Auth does) try { new URL(ssoConfig.issuer) } catch { @@ -402,7 +390,97 @@ async function registerSSOProvider(): Promise { return false } - // Check if provider already exists + if (ssoConfig.providerType === 'oidc' && ssoConfig.oidcConfig) { + const needsDiscovery = + !ssoConfig.oidcConfig.authorizationEndpoint || + !ssoConfig.oidcConfig.tokenEndpoint || + !ssoConfig.oidcConfig.jwksEndpoint + + if (needsDiscovery) { + const discoveryUrl = + ssoConfig.oidcConfig.discoveryEndpoint || + `${ssoConfig.issuer.replace(/\/$/, '')}/.well-known/openid-configuration` + logger.info('Fetching OIDC discovery document for missing endpoints...', { + discoveryUrl, + hasAuthEndpoint: !!ssoConfig.oidcConfig.authorizationEndpoint, + hasTokenEndpoint: !!ssoConfig.oidcConfig.tokenEndpoint, + hasJwksEndpoint: !!ssoConfig.oidcConfig.jwksEndpoint, + }) + + try { + const response = await fetch(discoveryUrl, { + headers: { Accept: 'application/json' }, + }) + + if (!response.ok) { + logger.error('Failed to fetch OIDC discovery document', { + status: response.status, + statusText: response.statusText, + }) + logger.error( + 'Provide all endpoints explicitly via SSO_OIDC_AUTHORIZATION_ENDPOINT, SSO_OIDC_TOKEN_ENDPOINT, SSO_OIDC_JWKS_ENDPOINT' + ) + return false + } + + const discovery = await response.json() + + ssoConfig.oidcConfig.authorizationEndpoint = + ssoConfig.oidcConfig.authorizationEndpoint || discovery.authorization_endpoint + ssoConfig.oidcConfig.tokenEndpoint = + ssoConfig.oidcConfig.tokenEndpoint || discovery.token_endpoint + ssoConfig.oidcConfig.userInfoEndpoint = + ssoConfig.oidcConfig.userInfoEndpoint || discovery.userinfo_endpoint + ssoConfig.oidcConfig.jwksEndpoint = + ssoConfig.oidcConfig.jwksEndpoint || discovery.jwks_uri + + logger.info('Merged OIDC endpoints (user-provided + discovery)', { + authorizationEndpoint: ssoConfig.oidcConfig.authorizationEndpoint, + tokenEndpoint: ssoConfig.oidcConfig.tokenEndpoint, + userInfoEndpoint: ssoConfig.oidcConfig.userInfoEndpoint, + jwksEndpoint: ssoConfig.oidcConfig.jwksEndpoint, + }) + } catch (error) { + logger.error('Error fetching OIDC discovery document', { + error: error instanceof Error ? error.message : 'Unknown error', + discoveryUrl, + }) + logger.error( + 'Please provide explicit endpoints via SSO_OIDC_AUTHORIZATION_ENDPOINT, SSO_OIDC_TOKEN_ENDPOINT, SSO_OIDC_JWKS_ENDPOINT' + ) + return false + } + } else { + logger.info('Using explicitly provided OIDC endpoints (all present)', { + authorizationEndpoint: ssoConfig.oidcConfig.authorizationEndpoint, + tokenEndpoint: ssoConfig.oidcConfig.tokenEndpoint, + userInfoEndpoint: ssoConfig.oidcConfig.userInfoEndpoint, + jwksEndpoint: ssoConfig.oidcConfig.jwksEndpoint, + }) + } + + if ( + !ssoConfig.oidcConfig.authorizationEndpoint || + !ssoConfig.oidcConfig.tokenEndpoint || + !ssoConfig.oidcConfig.jwksEndpoint + ) { + const missing: string[] = [] + if (!ssoConfig.oidcConfig.authorizationEndpoint) + missing.push('SSO_OIDC_AUTHORIZATION_ENDPOINT') + if (!ssoConfig.oidcConfig.tokenEndpoint) missing.push('SSO_OIDC_TOKEN_ENDPOINT') + if (!ssoConfig.oidcConfig.jwksEndpoint) missing.push('SSO_OIDC_JWKS_ENDPOINT') + + logger.error('Missing required OIDC endpoints after discovery merge', { + missing, + authorizationEndpoint: ssoConfig.oidcConfig.authorizationEndpoint, + tokenEndpoint: ssoConfig.oidcConfig.tokenEndpoint, + jwksEndpoint: ssoConfig.oidcConfig.jwksEndpoint, + }) + logger.error(`Please provide: ${missing.join(', ')}`) + return false + } + } + const existingProviders = await db .select() .from(ssoProvider) @@ -413,9 +491,8 @@ async function registerSSOProvider(): Promise { logger.info('Updating existing provider...') } - // Build provider data (following Better Auth's exact structure) const providerData: SSOProviderData = { - id: uuidv4(), // Generate unique ID + id: uuidv4(), issuer: ssoConfig.issuer, domain: ssoConfig.domain, userId: adminUser.id, @@ -423,7 +500,6 @@ async function registerSSOProvider(): Promise { organizationId: process.env.SSO_ORGANIZATION_ID || undefined, } - // Build OIDC config (same as Better Auth endpoint) if (ssoConfig.providerType === 'oidc' && ssoConfig.oidcConfig) { const oidcConfig = { issuer: ssoConfig.issuer, @@ -445,7 +521,6 @@ async function registerSSOProvider(): Promise { providerData.oidcConfig = JSON.stringify(oidcConfig) } - // Build SAML config (same as Better Auth endpoint) if (ssoConfig.providerType === 'saml' && ssoConfig.samlConfig) { const samlConfig = { issuer: ssoConfig.issuer, @@ -467,7 +542,6 @@ async function registerSSOProvider(): Promise { providerData.samlConfig = JSON.stringify(samlConfig) } - // Insert or update the SSO provider record if (existingProviders.length > 0) { await db .update(ssoProvider) @@ -521,7 +595,6 @@ async function main() { console.log('This script directly inserts SSO provider records into the database.') console.log("It follows Better Auth's exact registerSSOProvider logic.\n") - // Register the SSO provider using direct database access const success = await registerSSOProvider() if (success) { @@ -538,7 +611,6 @@ async function main() { } } -// Handle script execution main().catch((error) => { logger.error('Script execution failed:', { error }) process.exit(1)