workos 0.17.0 → 0.17.1

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.
@@ -116,7 +116,7 @@ function checkSignoutGetHandler(ctx) {
116
116
  message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',
117
117
  filePath: relative(ctx.installDir, route),
118
118
  remediation: 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',
119
- docsUrl: 'https://workos.com/docs/authkit/sign-out',
119
+ docsUrl: 'https://workos.com/docs/authkit/nextjs#ending-the-session',
120
120
  });
121
121
  }
122
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/sign-out',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx\n // Both conventions work in both src/ and app/ directories\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const prefix of ['src', 'app']) {\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));\n }\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation:\n 'Add authkitMiddleware to requestMiddleware in src/start.ts:\\n' +\n ' import { authkitMiddleware } from \"@workos/authkit-tanstack-react-start\";\\n' +\n ' export default createStart({ requestMiddleware: [authkitMiddleware()] });',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\nconst SECRET_SOURCE_IGNORED_SEGMENTS = new Set(['__fixtures__', '__tests__', 'evals', 'fixtures', 'test', 'tests']);\n\nfunction isIgnoredSecretSourcePath(relativePath: string): boolean {\n const normalized = relativePath.replace(/\\\\/g, '/');\n const parts = normalized.split('/');\n if (parts.some((part) => SECRET_SOURCE_IGNORED_SEGMENTS.has(part))) return true;\n return /\\.(spec|test)\\.[^.]+$/.test(normalized);\n}\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const relativePath = relative(ctx.installDir, file);\n if (isIgnoredSecretSourcePath(relativePath)) continue;\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relativePath,\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split(/\\r?\\n/).some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
1
+ {"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs#ending-the-session',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx\n // Both conventions work in both src/ and app/ directories\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const prefix of ['src', 'app']) {\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));\n }\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation:\n 'Add authkitMiddleware to requestMiddleware in src/start.ts:\\n' +\n ' import { authkitMiddleware } from \"@workos/authkit-tanstack-react-start\";\\n' +\n ' export default createStart({ requestMiddleware: [authkitMiddleware()] });',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\nconst SECRET_SOURCE_IGNORED_SEGMENTS = new Set(['__fixtures__', '__tests__', 'evals', 'fixtures', 'test', 'tests']);\n\nfunction isIgnoredSecretSourcePath(relativePath: string): boolean {\n const normalized = relativePath.replace(/\\\\/g, '/');\n const parts = normalized.split('/');\n if (parts.some((part) => SECRET_SOURCE_IGNORED_SEGMENTS.has(part))) return true;\n return /\\.(spec|test)\\.[^.]+$/.test(normalized);\n}\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const relativePath = relative(ctx.installDir, file);\n if (isIgnoredSecretSourcePath(relativePath)) continue;\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relativePath,\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split(/\\r?\\n/).some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { getReference } from '@workos/skills';
2
2
  import { SPINNER_MESSAGE } from './framework-config.js';
3
3
  import { validateInstallation, quickCheckValidateAndFormat } from './validation/index.js';
4
+ import { runInstallSecurityChecks, securityFindingsToIssues, formatSecurityFindingsForAgent, formatBlockingSecurityError, } from './validation/security-checks.js';
4
5
  import { ensurePackageIsInstalled, getOrAskForWorkOSCredentials, getPackageDotJson, isUsingTypeScript, } from '../utils/clack-utils.js';
5
6
  import { analytics } from '../utils/analytics.js';
6
7
  import { INSTALLER_INTERACTION_EVENT_NAME } from './constants.js';
@@ -82,11 +83,27 @@ export async function runAgentInstaller(config, options) {
82
83
  workOSApiKey: apiKey,
83
84
  workOSApiHost: 'https://api.workos.com',
84
85
  }, options);
86
+ const integration = config.metadata.integration;
85
87
  const retryConfig = options.noValidate
86
88
  ? undefined
87
89
  : {
88
90
  maxRetries: options.maxRetries ?? 2,
89
- validateAndFormat: quickCheckValidateAndFormat,
91
+ // Self-correction combines two layers: build/typecheck (existing) AND the
92
+ // security subset of doctor's auth-pattern checks. The latter is what was
93
+ // missing — it's why an insecure GET sign-out could pass the build and
94
+ // ship as a "successful" install. Only error-severity security findings
95
+ // force a retry; warning findings ride along in the prompt only when a
96
+ // retry is already triggered by an error or a build failure (warnings are
97
+ // still surfaced in the final validation report regardless).
98
+ validateAndFormat: async (workingDirectory) => {
99
+ const quickPrompt = await quickCheckValidateAndFormat(workingDirectory);
100
+ const security = await runInstallSecurityChecks(integration, workingDirectory);
101
+ if (quickPrompt === null && security.blocking.length === 0)
102
+ return null;
103
+ return [quickPrompt, formatSecurityFindingsForAgent(security.findings)]
104
+ .filter((p) => Boolean(p))
105
+ .join('\n\n');
106
+ },
90
107
  };
91
108
  // Run agent with retry support — agent gets correction prompts on validation failure
92
109
  const agentResult = await runAgent(agent, integrationPrompt, options, {
@@ -102,30 +119,52 @@ export async function runAgentInstaller(config, options) {
102
119
  // "Agent SDK error:" — that prefix obscures the actionable text.
103
120
  throw new Error(message);
104
121
  }
105
- // Track retry metrics
106
- if (agentResult.retryCount !== undefined && agentResult.retryCount > 0) {
107
- analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {
108
- action: 'agent retry summary',
109
- retry_count: agentResult.retryCount,
110
- max_retries: options.maxRetries ?? 2,
111
- passed_after_retry: true,
112
- });
113
- }
114
122
  // Run full validation after agent (with retries) completes
115
123
  // Quick checks already ran inside the retry loop — skip build
116
124
  if (!options.noValidate) {
117
- options.emitter?.emit('validation:start', { framework: config.metadata.integration });
118
- const validationResult = await validateInstallation(config.metadata.integration, options.installDir, {
125
+ options.emitter?.emit('validation:start', { framework: integration });
126
+ const validationResult = await validateInstallation(integration, options.installDir, {
119
127
  runBuild: false,
120
128
  });
121
- if (validationResult.issues.length > 0) {
122
- options.emitter?.emit('validation:issues', { issues: validationResult.issues });
129
+ // Run doctor's security subset as the final gate. Its absence here is the
130
+ // install-validate ↔ doctor gap: install reported success while `workos
131
+ // doctor` immediately found a SIGNOUT_GET_HANDLER hole.
132
+ const security = await runInstallSecurityChecks(integration, options.installDir);
133
+ const allIssues = [...validationResult.issues, ...securityFindingsToIssues(security.findings)];
134
+ if (allIssues.length > 0) {
135
+ options.emitter?.emit('validation:issues', { issues: allIssues });
123
136
  }
124
137
  options.emitter?.emit('validation:complete', {
125
- passed: validationResult.passed,
126
- issueCount: validationResult.issues.length,
138
+ passed: validationResult.passed && security.blocking.length === 0,
139
+ issueCount: allIssues.length,
127
140
  durationMs: validationResult.durationMs,
128
141
  });
142
+ // Block success: an error-severity security finding that survived the
143
+ // self-correction retries fails the install rather than shipping silently.
144
+ // Throwing routes through the state machine's error state (success: false,
145
+ // non-zero exit) and skips the commit/PR steps, leaving the insecure code
146
+ // uncommitted for the user to inspect.
147
+ if (security.blocking.length > 0) {
148
+ analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {
149
+ action: 'security gate blocked install',
150
+ integration,
151
+ codes: security.blocking.map((f) => f.code).join(','),
152
+ });
153
+ await analytics.shutdown('error');
154
+ throw new Error(formatBlockingSecurityError(security.blocking));
155
+ }
156
+ }
157
+ // Track retry metrics AFTER the security gate. `passed_after_retry` must
158
+ // reflect a genuinely successful install, not just an exhausted retry loop —
159
+ // emitting it before the gate could pair a "passed after retry" event with a
160
+ // "security gate blocked install" failure for the same run.
161
+ if (agentResult.retryCount !== undefined && agentResult.retryCount > 0) {
162
+ analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {
163
+ action: 'agent retry summary',
164
+ retry_count: agentResult.retryCount,
165
+ max_retries: options.maxRetries ?? 2,
166
+ passed_after_retry: true,
167
+ });
129
168
  }
130
169
  // Build environment variables from WorkOS credentials
131
170
  const envVars = config.environment.getEnvVars(apiKey, clientId);
@@ -1 +1 @@
1
- {"version":3,"file":"agent-runner.js","sourceRoot":"","sources":["../../src/lib/agent-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { getReference } from '@workos/skills';\nimport { SPINNER_MESSAGE, type FrameworkConfig } from './framework-config.js';\nimport { validateInstallation, quickCheckValidateAndFormat } from './validation/index.js';\nimport type { InstallerOptions } from '../utils/types.js';\nimport {\n ensurePackageIsInstalled,\n getOrAskForWorkOSCredentials,\n getPackageDotJson,\n isUsingTypeScript,\n} from '../utils/clack-utils.js';\nimport { analytics } from '../utils/analytics.js';\nimport { INSTALLER_INTERACTION_EVENT_NAME } from './constants.js';\nimport { initializeAgent, runAgent, type RetryConfig } from './agent-interface.js';\nimport { uploadEnvironmentVariablesStep } from '../steps/index.js';\nimport { autoConfigureWorkOSEnvironment } from './workos-management.js';\nimport { detectPort, getCallbackPath } from './port-detection.js';\nimport { writeEnvLocal } from './env-writer.js';\n\n/**\n * Universal agent-powered wizard runner.\n * Handles the complete flow for any framework using WorkOS MCP integration.\n *\n * @returns A detailed summary of what was done and next steps\n */\nexport async function runAgentInstaller(config: FrameworkConfig, options: InstallerOptions): Promise<string> {\n // Emit status for UI adapters to render\n options.emitter?.emit('status', {\n message: `Setting up WorkOS AuthKit for ${config.metadata.name}`,\n });\n\n const typeScriptDetected = isUsingTypeScript(options);\n\n // Git check is now handled by the state machine - no need to check here\n\n // Framework detection and version\n const packageJson = await getPackageDotJson(options);\n await ensurePackageIsInstalled(packageJson, config.detection.packageName, config.detection.packageDisplayName);\n\n const frameworkVersion = config.detection.getVersion(packageJson);\n\n // Set analytics tags for framework version\n if (frameworkVersion && config.detection.getVersionBucket) {\n const versionBucket = config.detection.getVersionBucket(frameworkVersion);\n analytics.setTag(`${config.metadata.integration}-version`, versionBucket);\n }\n\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'started agent integration',\n integration: config.metadata.integration,\n });\n\n // Get WorkOS credentials (API key optional for client-only SDKs)\n const { apiKey, clientId } = await getOrAskForWorkOSCredentials(options, config.environment.requiresApiKey);\n\n // Check if caller (state machine) already configured WorkOS environment\n // If credentials were passed via options, the caller handled config+env writing\n const callerHandledConfig = Boolean(options.apiKey || options.clientId);\n\n // Auto-configure WorkOS environment (redirect URI, CORS, homepage)\n // Skip if caller already handled this (prevents duplicate dashboard config output)\n if (!callerHandledConfig && apiKey && config.environment.requiresApiKey) {\n const port = detectPort(config.metadata.integration, options.installDir);\n await autoConfigureWorkOSEnvironment(apiKey, config.metadata.integration, port, {\n homepageUrl: options.homepageUrl,\n redirectUri: options.redirectUri,\n });\n }\n\n // Gather framework-specific context (e.g., Next.js router, React Native platform)\n const frameworkContext = config.metadata.gatherContext ? await config.metadata.gatherContext(options) : {};\n\n // Write environment variables to .env.local BEFORE agent runs\n // Skip if caller already handled this (prevents double-writing)\n if (!callerHandledConfig) {\n const port = detectPort(config.metadata.integration, options.installDir);\n const callbackPath = getCallbackPath(config.metadata.integration);\n const redirectUri = options.redirectUri || `http://localhost:${port}${callbackPath}`;\n\n // Next.js requires NEXT_PUBLIC_ prefix for client-side env vars\n const redirectUriKey =\n config.metadata.integration === 'nextjs' ? 'NEXT_PUBLIC_WORKOS_REDIRECT_URI' : 'WORKOS_REDIRECT_URI';\n\n writeEnvLocal(options.installDir, {\n ...(apiKey ? { WORKOS_API_KEY: apiKey } : {}),\n WORKOS_CLIENT_ID: clientId,\n [redirectUriKey]: redirectUri,\n });\n }\n\n // Set analytics tags from framework context\n const contextTags = config.analytics.getTags(frameworkContext);\n Object.entries(contextTags).forEach(([key, value]) => {\n analytics.setTag(key, value);\n });\n\n // Build integration prompt (credentials are already in .env.local)\n const integrationPrompt = await buildIntegrationPrompt(\n config,\n {\n frameworkVersion: frameworkVersion || 'latest',\n typescript: typeScriptDetected,\n },\n frameworkContext,\n );\n\n // Initialize and run agent\n // Spinner is now handled by adapters listening to agent:start/agent:progress events\n const agent = await initializeAgent(\n {\n workingDirectory: options.installDir,\n workOSApiKey: apiKey,\n workOSApiHost: 'https://api.workos.com',\n },\n options,\n );\n\n const retryConfig: RetryConfig | undefined = options.noValidate\n ? undefined\n : {\n maxRetries: options.maxRetries ?? 2,\n validateAndFormat: quickCheckValidateAndFormat,\n };\n\n // Run agent with retry support — agent gets correction prompts on validation failure\n const agentResult = await runAgent(\n agent,\n integrationPrompt,\n options,\n {\n spinnerMessage: SPINNER_MESSAGE,\n successMessage: config.ui.successMessage,\n errorMessage: 'Integration failed',\n },\n options.emitter,\n retryConfig,\n );\n\n // If agent returned an error, throw so state machine can handle it\n if (agentResult.error) {\n await analytics.shutdown('error');\n const message = agentResult.errorMessage || agentResult.error;\n // Pass user-friendly messages through without wrapping them in\n // \"Agent SDK error:\" — that prefix obscures the actionable text.\n throw new Error(message);\n }\n\n // Track retry metrics\n if (agentResult.retryCount !== undefined && agentResult.retryCount > 0) {\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'agent retry summary',\n retry_count: agentResult.retryCount,\n max_retries: options.maxRetries ?? 2,\n passed_after_retry: true,\n });\n }\n\n // Run full validation after agent (with retries) completes\n // Quick checks already ran inside the retry loop — skip build\n if (!options.noValidate) {\n options.emitter?.emit('validation:start', { framework: config.metadata.integration });\n\n const validationResult = await validateInstallation(config.metadata.integration, options.installDir, {\n runBuild: false,\n });\n\n if (validationResult.issues.length > 0) {\n options.emitter?.emit('validation:issues', { issues: validationResult.issues });\n }\n\n options.emitter?.emit('validation:complete', {\n passed: validationResult.passed,\n issueCount: validationResult.issues.length,\n durationMs: validationResult.durationMs,\n });\n }\n\n // Build environment variables from WorkOS credentials\n const envVars = config.environment.getEnvVars(apiKey, clientId);\n\n // Upload environment variables to hosting providers (if configured)\n let uploadedEnvVars: string[] = [];\n if (config.environment.uploadToHosting) {\n uploadedEnvVars = await uploadEnvironmentVariablesStep(envVars, {\n integration: config.metadata.integration,\n options,\n });\n }\n\n const changes = [\n ...config.ui.getOutroChanges(frameworkContext),\n Object.keys(envVars).length > 0 ? `Added environment variables to .env file` : '',\n uploadedEnvVars.length > 0 ? `Uploaded environment variables to your hosting provider` : '',\n ].filter(Boolean);\n\n const nextSteps = [\n ...config.ui.getOutroNextSteps(frameworkContext),\n uploadedEnvVars.length === 0 && config.environment.uploadToHosting\n ? `Upload your WorkOS credentials to your hosting provider`\n : '',\n ].filter(Boolean);\n\n const summary = buildCompletionSummary(config, changes, nextSteps);\n\n await analytics.shutdown('success');\n\n return summary;\n}\n\n/**\n * Build the integration prompt for the agent.\n * Reads reference content from @workos/skills and injects it directly into the prompt.\n * Note: Credentials are pre-written to .env.local, so not included in prompt.\n */\nasync function buildIntegrationPrompt(\n config: FrameworkConfig,\n context: {\n frameworkVersion: string;\n typescript: boolean;\n },\n frameworkContext: Record<string, any>,\n): Promise<string> {\n const additionalLines = config.prompts.getAdditionalContextLines\n ? config.prompts.getAdditionalContextLines(frameworkContext)\n : [];\n\n const additionalContext =\n additionalLines.length > 0 ? '\\n' + additionalLines.map((line) => `- ${line}`).join('\\n') : '';\n\n const skillName = config.metadata.skillName;\n if (!skillName) {\n throw new Error(`Framework ${config.metadata.name} missing skillName in config`);\n }\n\n // Read reference content from @workos/skills package\n // Base template has JS-centric assumptions (node_modules, lockfiles, AuthKitProvider)\n // so only load it for JavaScript integrations; backend SDKs bypass this entirely\n const isJavaScript = config.metadata.language === 'javascript';\n const [baseContent, refContent] = await Promise.all([\n isJavaScript ? getReference('workos-authkit-base') : Promise.resolve(''),\n getReference(skillName),\n ]);\n\n // Build env var list dynamically based on what was actually configured\n const envVars = [\n ...(config.environment.requiresApiKey ? ['WORKOS_API_KEY'] : []),\n 'WORKOS_CLIENT_ID',\n config.metadata.integration === 'nextjs' ? 'NEXT_PUBLIC_WORKOS_REDIRECT_URI' : 'WORKOS_REDIRECT_URI',\n 'WORKOS_COOKIE_PASSWORD',\n ];\n const envVarList = envVars.map((v) => `- ${v}`).join('\\n');\n\n return `You are integrating WorkOS AuthKit into this ${config.metadata.name} application.\n\n## Project Context\n\n- Framework: ${config.metadata.name} ${context.frameworkVersion}\n- TypeScript: ${context.typescript ? 'Yes' : 'No'}${additionalContext}\n\n## Environment\n\nThe following environment variables have been configured in .env.local:\n${envVarList}\n\n${baseContent ? `## General Guidelines\\n\\n${baseContent}\\n\\n` : ''}## Integration Instructions\n\n${refContent}\n\nReport your progress using [STATUS] prefixes.\n\nBegin integration now.`;\n}\n\nfunction buildCompletionSummary(config: FrameworkConfig, changes: string[], nextSteps: string[]): string {\n const lines: string[] = ['Successfully installed WorkOS AuthKit!', ''];\n\n if (changes.length > 0) {\n lines.push('What the agent did:');\n for (const change of changes) lines.push(`• ${change}`);\n lines.push('');\n }\n\n if (nextSteps.length > 0) {\n lines.push('Next steps:');\n for (const step of nextSteps) lines.push(`• ${step}`);\n lines.push('');\n }\n\n lines.push(\n `Learn more: ${config.metadata.docsUrl}`,\n '',\n 'Note: This installer uses an LLM agent to analyze and modify your project. Please review the changes made.',\n );\n\n return lines.join('\\n');\n}\n"]}
1
+ {"version":3,"file":"agent-runner.js","sourceRoot":"","sources":["../../src/lib/agent-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { getReference } from '@workos/skills';\nimport { SPINNER_MESSAGE, type FrameworkConfig } from './framework-config.js';\nimport { validateInstallation, quickCheckValidateAndFormat } from './validation/index.js';\nimport {\n runInstallSecurityChecks,\n securityFindingsToIssues,\n formatSecurityFindingsForAgent,\n formatBlockingSecurityError,\n} from './validation/security-checks.js';\nimport type { InstallerOptions } from '../utils/types.js';\nimport {\n ensurePackageIsInstalled,\n getOrAskForWorkOSCredentials,\n getPackageDotJson,\n isUsingTypeScript,\n} from '../utils/clack-utils.js';\nimport { analytics } from '../utils/analytics.js';\nimport { INSTALLER_INTERACTION_EVENT_NAME } from './constants.js';\nimport { initializeAgent, runAgent, type RetryConfig } from './agent-interface.js';\nimport { uploadEnvironmentVariablesStep } from '../steps/index.js';\nimport { autoConfigureWorkOSEnvironment } from './workos-management.js';\nimport { detectPort, getCallbackPath } from './port-detection.js';\nimport { writeEnvLocal } from './env-writer.js';\n\n/**\n * Universal agent-powered wizard runner.\n * Handles the complete flow for any framework using WorkOS MCP integration.\n *\n * @returns A detailed summary of what was done and next steps\n */\nexport async function runAgentInstaller(config: FrameworkConfig, options: InstallerOptions): Promise<string> {\n // Emit status for UI adapters to render\n options.emitter?.emit('status', {\n message: `Setting up WorkOS AuthKit for ${config.metadata.name}`,\n });\n\n const typeScriptDetected = isUsingTypeScript(options);\n\n // Git check is now handled by the state machine - no need to check here\n\n // Framework detection and version\n const packageJson = await getPackageDotJson(options);\n await ensurePackageIsInstalled(packageJson, config.detection.packageName, config.detection.packageDisplayName);\n\n const frameworkVersion = config.detection.getVersion(packageJson);\n\n // Set analytics tags for framework version\n if (frameworkVersion && config.detection.getVersionBucket) {\n const versionBucket = config.detection.getVersionBucket(frameworkVersion);\n analytics.setTag(`${config.metadata.integration}-version`, versionBucket);\n }\n\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'started agent integration',\n integration: config.metadata.integration,\n });\n\n // Get WorkOS credentials (API key optional for client-only SDKs)\n const { apiKey, clientId } = await getOrAskForWorkOSCredentials(options, config.environment.requiresApiKey);\n\n // Check if caller (state machine) already configured WorkOS environment\n // If credentials were passed via options, the caller handled config+env writing\n const callerHandledConfig = Boolean(options.apiKey || options.clientId);\n\n // Auto-configure WorkOS environment (redirect URI, CORS, homepage)\n // Skip if caller already handled this (prevents duplicate dashboard config output)\n if (!callerHandledConfig && apiKey && config.environment.requiresApiKey) {\n const port = detectPort(config.metadata.integration, options.installDir);\n await autoConfigureWorkOSEnvironment(apiKey, config.metadata.integration, port, {\n homepageUrl: options.homepageUrl,\n redirectUri: options.redirectUri,\n });\n }\n\n // Gather framework-specific context (e.g., Next.js router, React Native platform)\n const frameworkContext = config.metadata.gatherContext ? await config.metadata.gatherContext(options) : {};\n\n // Write environment variables to .env.local BEFORE agent runs\n // Skip if caller already handled this (prevents double-writing)\n if (!callerHandledConfig) {\n const port = detectPort(config.metadata.integration, options.installDir);\n const callbackPath = getCallbackPath(config.metadata.integration);\n const redirectUri = options.redirectUri || `http://localhost:${port}${callbackPath}`;\n\n // Next.js requires NEXT_PUBLIC_ prefix for client-side env vars\n const redirectUriKey =\n config.metadata.integration === 'nextjs' ? 'NEXT_PUBLIC_WORKOS_REDIRECT_URI' : 'WORKOS_REDIRECT_URI';\n\n writeEnvLocal(options.installDir, {\n ...(apiKey ? { WORKOS_API_KEY: apiKey } : {}),\n WORKOS_CLIENT_ID: clientId,\n [redirectUriKey]: redirectUri,\n });\n }\n\n // Set analytics tags from framework context\n const contextTags = config.analytics.getTags(frameworkContext);\n Object.entries(contextTags).forEach(([key, value]) => {\n analytics.setTag(key, value);\n });\n\n // Build integration prompt (credentials are already in .env.local)\n const integrationPrompt = await buildIntegrationPrompt(\n config,\n {\n frameworkVersion: frameworkVersion || 'latest',\n typescript: typeScriptDetected,\n },\n frameworkContext,\n );\n\n // Initialize and run agent\n // Spinner is now handled by adapters listening to agent:start/agent:progress events\n const agent = await initializeAgent(\n {\n workingDirectory: options.installDir,\n workOSApiKey: apiKey,\n workOSApiHost: 'https://api.workos.com',\n },\n options,\n );\n\n const integration = config.metadata.integration;\n\n const retryConfig: RetryConfig | undefined = options.noValidate\n ? undefined\n : {\n maxRetries: options.maxRetries ?? 2,\n // Self-correction combines two layers: build/typecheck (existing) AND the\n // security subset of doctor's auth-pattern checks. The latter is what was\n // missing — it's why an insecure GET sign-out could pass the build and\n // ship as a \"successful\" install. Only error-severity security findings\n // force a retry; warning findings ride along in the prompt only when a\n // retry is already triggered by an error or a build failure (warnings are\n // still surfaced in the final validation report regardless).\n validateAndFormat: async (workingDirectory: string) => {\n const quickPrompt = await quickCheckValidateAndFormat(workingDirectory);\n const security = await runInstallSecurityChecks(integration, workingDirectory);\n if (quickPrompt === null && security.blocking.length === 0) return null;\n return [quickPrompt, formatSecurityFindingsForAgent(security.findings)]\n .filter((p): p is string => Boolean(p))\n .join('\\n\\n');\n },\n };\n\n // Run agent with retry support — agent gets correction prompts on validation failure\n const agentResult = await runAgent(\n agent,\n integrationPrompt,\n options,\n {\n spinnerMessage: SPINNER_MESSAGE,\n successMessage: config.ui.successMessage,\n errorMessage: 'Integration failed',\n },\n options.emitter,\n retryConfig,\n );\n\n // If agent returned an error, throw so state machine can handle it\n if (agentResult.error) {\n await analytics.shutdown('error');\n const message = agentResult.errorMessage || agentResult.error;\n // Pass user-friendly messages through without wrapping them in\n // \"Agent SDK error:\" — that prefix obscures the actionable text.\n throw new Error(message);\n }\n\n // Run full validation after agent (with retries) completes\n // Quick checks already ran inside the retry loop — skip build\n if (!options.noValidate) {\n options.emitter?.emit('validation:start', { framework: integration });\n\n const validationResult = await validateInstallation(integration, options.installDir, {\n runBuild: false,\n });\n\n // Run doctor's security subset as the final gate. Its absence here is the\n // install-validate ↔ doctor gap: install reported success while `workos\n // doctor` immediately found a SIGNOUT_GET_HANDLER hole.\n const security = await runInstallSecurityChecks(integration, options.installDir);\n const allIssues = [...validationResult.issues, ...securityFindingsToIssues(security.findings)];\n\n if (allIssues.length > 0) {\n options.emitter?.emit('validation:issues', { issues: allIssues });\n }\n\n options.emitter?.emit('validation:complete', {\n passed: validationResult.passed && security.blocking.length === 0,\n issueCount: allIssues.length,\n durationMs: validationResult.durationMs,\n });\n\n // Block success: an error-severity security finding that survived the\n // self-correction retries fails the install rather than shipping silently.\n // Throwing routes through the state machine's error state (success: false,\n // non-zero exit) and skips the commit/PR steps, leaving the insecure code\n // uncommitted for the user to inspect.\n if (security.blocking.length > 0) {\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'security gate blocked install',\n integration,\n codes: security.blocking.map((f) => f.code).join(','),\n });\n await analytics.shutdown('error');\n throw new Error(formatBlockingSecurityError(security.blocking));\n }\n }\n\n // Track retry metrics AFTER the security gate. `passed_after_retry` must\n // reflect a genuinely successful install, not just an exhausted retry loop —\n // emitting it before the gate could pair a \"passed after retry\" event with a\n // \"security gate blocked install\" failure for the same run.\n if (agentResult.retryCount !== undefined && agentResult.retryCount > 0) {\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'agent retry summary',\n retry_count: agentResult.retryCount,\n max_retries: options.maxRetries ?? 2,\n passed_after_retry: true,\n });\n }\n\n // Build environment variables from WorkOS credentials\n const envVars = config.environment.getEnvVars(apiKey, clientId);\n\n // Upload environment variables to hosting providers (if configured)\n let uploadedEnvVars: string[] = [];\n if (config.environment.uploadToHosting) {\n uploadedEnvVars = await uploadEnvironmentVariablesStep(envVars, {\n integration: config.metadata.integration,\n options,\n });\n }\n\n const changes = [\n ...config.ui.getOutroChanges(frameworkContext),\n Object.keys(envVars).length > 0 ? `Added environment variables to .env file` : '',\n uploadedEnvVars.length > 0 ? `Uploaded environment variables to your hosting provider` : '',\n ].filter(Boolean);\n\n const nextSteps = [\n ...config.ui.getOutroNextSteps(frameworkContext),\n uploadedEnvVars.length === 0 && config.environment.uploadToHosting\n ? `Upload your WorkOS credentials to your hosting provider`\n : '',\n ].filter(Boolean);\n\n const summary = buildCompletionSummary(config, changes, nextSteps);\n\n await analytics.shutdown('success');\n\n return summary;\n}\n\n/**\n * Build the integration prompt for the agent.\n * Reads reference content from @workos/skills and injects it directly into the prompt.\n * Note: Credentials are pre-written to .env.local, so not included in prompt.\n */\nasync function buildIntegrationPrompt(\n config: FrameworkConfig,\n context: {\n frameworkVersion: string;\n typescript: boolean;\n },\n frameworkContext: Record<string, any>,\n): Promise<string> {\n const additionalLines = config.prompts.getAdditionalContextLines\n ? config.prompts.getAdditionalContextLines(frameworkContext)\n : [];\n\n const additionalContext =\n additionalLines.length > 0 ? '\\n' + additionalLines.map((line) => `- ${line}`).join('\\n') : '';\n\n const skillName = config.metadata.skillName;\n if (!skillName) {\n throw new Error(`Framework ${config.metadata.name} missing skillName in config`);\n }\n\n // Read reference content from @workos/skills package\n // Base template has JS-centric assumptions (node_modules, lockfiles, AuthKitProvider)\n // so only load it for JavaScript integrations; backend SDKs bypass this entirely\n const isJavaScript = config.metadata.language === 'javascript';\n const [baseContent, refContent] = await Promise.all([\n isJavaScript ? getReference('workos-authkit-base') : Promise.resolve(''),\n getReference(skillName),\n ]);\n\n // Build env var list dynamically based on what was actually configured\n const envVars = [\n ...(config.environment.requiresApiKey ? ['WORKOS_API_KEY'] : []),\n 'WORKOS_CLIENT_ID',\n config.metadata.integration === 'nextjs' ? 'NEXT_PUBLIC_WORKOS_REDIRECT_URI' : 'WORKOS_REDIRECT_URI',\n 'WORKOS_COOKIE_PASSWORD',\n ];\n const envVarList = envVars.map((v) => `- ${v}`).join('\\n');\n\n return `You are integrating WorkOS AuthKit into this ${config.metadata.name} application.\n\n## Project Context\n\n- Framework: ${config.metadata.name} ${context.frameworkVersion}\n- TypeScript: ${context.typescript ? 'Yes' : 'No'}${additionalContext}\n\n## Environment\n\nThe following environment variables have been configured in .env.local:\n${envVarList}\n\n${baseContent ? `## General Guidelines\\n\\n${baseContent}\\n\\n` : ''}## Integration Instructions\n\n${refContent}\n\nReport your progress using [STATUS] prefixes.\n\nBegin integration now.`;\n}\n\nfunction buildCompletionSummary(config: FrameworkConfig, changes: string[], nextSteps: string[]): string {\n const lines: string[] = ['Successfully installed WorkOS AuthKit!', ''];\n\n if (changes.length > 0) {\n lines.push('What the agent did:');\n for (const change of changes) lines.push(`• ${change}`);\n lines.push('');\n }\n\n if (nextSteps.length > 0) {\n lines.push('Next steps:');\n for (const step of nextSteps) lines.push(`• ${step}`);\n lines.push('');\n }\n\n lines.push(\n `Learn more: ${config.metadata.docsUrl}`,\n '',\n 'Note: This installer uses an LLM agent to analyze and modify your project. Please review the changes made.',\n );\n\n return lines.join('\\n');\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import type { AuthPatternFinding } from '../../doctor/types.js';
2
+ import type { ValidationIssue } from './types.js';
3
+ export interface SecurityCheckResult {
4
+ /** All security-class findings for this install (errors + warnings). */
5
+ findings: AuthPatternFinding[];
6
+ /**
7
+ * Error-severity findings that must block a successful install. Empty when the
8
+ * install is secure; a non-empty list means install should not report success.
9
+ */
10
+ blocking: AuthPatternFinding[];
11
+ }
12
+ /**
13
+ * Run the security subset of doctor's auth-pattern checks against an install
14
+ * directory. Pure file inspection — no network — so it is safe to call both
15
+ * inside the installer's self-correction loop and as the final pre-success gate.
16
+ *
17
+ * This closes the install-validate ↔ doctor gap: previously install could report
18
+ * `success: true` while `workos doctor` immediately found a security hole,
19
+ * because neither the retry loop nor `validateInstallation` ran these checks.
20
+ */
21
+ export declare function runInstallSecurityChecks(integration: string, installDir: string): Promise<SecurityCheckResult>;
22
+ /** Convert security findings into ValidationIssues for the emitter/report surfaces. */
23
+ export declare function securityFindingsToIssues(findings: AuthPatternFinding[]): ValidationIssue[];
24
+ /**
25
+ * Build an agent correction prompt from security findings so the installer's
26
+ * self-correction loop fixes them before declaring success. Returns an empty
27
+ * string when there is nothing to correct.
28
+ */
29
+ export declare function formatSecurityFindingsForAgent(findings: AuthPatternFinding[]): string;
30
+ /**
31
+ * Build the error message thrown when error-severity security findings survive
32
+ * the installer's retries — the message that turns a silent insecure "success"
33
+ * into a visible failure.
34
+ */
35
+ export declare function formatBlockingSecurityError(blocking: AuthPatternFinding[]): string;
@@ -0,0 +1,105 @@
1
+ import { checkAuthPatterns } from '../../doctor/checks/auth-patterns.js';
2
+ /**
3
+ * The "security subset" of `workos doctor`'s auth-pattern checks that the
4
+ * installer enforces. These are the patterns that are *unsafe* or *leak secrets*
5
+ * (an unsafe GET sign-out, an API key in client env/source, an ungitignored
6
+ * .env). Completeness checks (missing middleware/callback/provider) are
7
+ * intentionally excluded here — `validateInstallation` already covers those, and
8
+ * they carry higher false-positive risk than we want gating install success.
9
+ *
10
+ * Keep in sync with the codes emitted by `src/doctor/checks/auth-patterns.ts`.
11
+ */
12
+ const SECURITY_FINDING_CODES = new Set([
13
+ 'SIGNOUT_GET_HANDLER',
14
+ 'SIGNOUT_LINK_PREFETCH',
15
+ 'API_KEY_LEAKED_TO_CLIENT',
16
+ 'API_KEY_IN_SOURCE',
17
+ 'ENV_FILE_NOT_GITIGNORED',
18
+ 'MIXED_ENVIRONMENT',
19
+ ]);
20
+ /** Map an installer integration id to the framework name doctor's checks expect. */
21
+ const INTEGRATION_FRAMEWORK_NAME = {
22
+ nextjs: 'Next.js',
23
+ 'react-router': 'React Router',
24
+ 'tanstack-start': 'TanStack Start',
25
+ };
26
+ /**
27
+ * Run the security subset of doctor's auth-pattern checks against an install
28
+ * directory. Pure file inspection — no network — so it is safe to call both
29
+ * inside the installer's self-correction loop and as the final pre-success gate.
30
+ *
31
+ * This closes the install-validate ↔ doctor gap: previously install could report
32
+ * `success: true` while `workos doctor` immediately found a security hole,
33
+ * because neither the retry loop nor `validateInstallation` ran these checks.
34
+ */
35
+ export async function runInstallSecurityChecks(integration, installDir) {
36
+ const framework = {
37
+ name: INTEGRATION_FRAMEWORK_NAME[integration] ?? null,
38
+ version: null,
39
+ };
40
+ // checkAuthPatterns loads .env files itself; these structs only satisfy the
41
+ // shape its non-Next.js checks read from.
42
+ const environment = {
43
+ apiKeyConfigured: false,
44
+ apiKeyType: null,
45
+ clientId: null,
46
+ redirectUri: null,
47
+ cookieDomain: null,
48
+ baseUrl: null,
49
+ };
50
+ const sdk = {
51
+ name: null,
52
+ version: null,
53
+ latest: null,
54
+ outdated: false,
55
+ isAuthKit: false,
56
+ language: 'javascript',
57
+ };
58
+ const result = await checkAuthPatterns({ installDir }, framework, environment, sdk);
59
+ const findings = result.findings.filter((f) => SECURITY_FINDING_CODES.has(f.code));
60
+ const blocking = findings.filter((f) => f.severity === 'error');
61
+ return { findings, blocking };
62
+ }
63
+ /** Convert security findings into ValidationIssues for the emitter/report surfaces. */
64
+ export function securityFindingsToIssues(findings) {
65
+ return findings.map((f) => ({
66
+ type: 'pattern',
67
+ severity: f.severity,
68
+ message: f.filePath ? `${f.message} (${f.filePath})` : f.message,
69
+ hint: f.remediation,
70
+ }));
71
+ }
72
+ /**
73
+ * Build an agent correction prompt from security findings so the installer's
74
+ * self-correction loop fixes them before declaring success. Returns an empty
75
+ * string when there is nothing to correct.
76
+ */
77
+ export function formatSecurityFindingsForAgent(findings) {
78
+ if (findings.length === 0)
79
+ return '';
80
+ const lines = findings.map((f) => {
81
+ const loc = f.filePath ? ` in ${f.filePath}` : '';
82
+ const fix = f.remediation ? ` Fix: ${f.remediation}` : '';
83
+ return `- [${f.severity}] ${f.message}${loc}.${fix}`;
84
+ });
85
+ return `Security checks found issues that must be fixed:\n\n${lines.join('\n')}\n\nApply the fixes above, then make sure the project still builds.`;
86
+ }
87
+ /**
88
+ * Build the error message thrown when error-severity security findings survive
89
+ * the installer's retries — the message that turns a silent insecure "success"
90
+ * into a visible failure.
91
+ */
92
+ export function formatBlockingSecurityError(blocking) {
93
+ const lines = blocking.map((f) => {
94
+ const loc = f.filePath ? ` (${f.filePath})` : '';
95
+ return ` • ${f.code}: ${f.message}${loc}`;
96
+ });
97
+ return [
98
+ 'Installation produced insecure code that could not be auto-corrected:',
99
+ '',
100
+ ...lines,
101
+ '',
102
+ 'Fix the issues above (or run `workos doctor` for details and remediation) and re-run the installer.',
103
+ ].join('\n');
104
+ }
105
+ //# sourceMappingURL=security-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-checks.js","sourceRoot":"","sources":["../../../src/lib/validation/security-checks.ts"],"names":[],"mappings":"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","sourcesContent":["import { checkAuthPatterns } from '../../doctor/checks/auth-patterns.js';\nimport type { AuthPatternFinding, FrameworkInfo, EnvironmentInfo, SdkInfo } from '../../doctor/types.js';\nimport type { ValidationIssue } from './types.js';\n\n/**\n * The \"security subset\" of `workos doctor`'s auth-pattern checks that the\n * installer enforces. These are the patterns that are *unsafe* or *leak secrets*\n * (an unsafe GET sign-out, an API key in client env/source, an ungitignored\n * .env). Completeness checks (missing middleware/callback/provider) are\n * intentionally excluded here — `validateInstallation` already covers those, and\n * they carry higher false-positive risk than we want gating install success.\n *\n * Keep in sync with the codes emitted by `src/doctor/checks/auth-patterns.ts`.\n */\nconst SECURITY_FINDING_CODES = new Set<string>([\n 'SIGNOUT_GET_HANDLER',\n 'SIGNOUT_LINK_PREFETCH',\n 'API_KEY_LEAKED_TO_CLIENT',\n 'API_KEY_IN_SOURCE',\n 'ENV_FILE_NOT_GITIGNORED',\n 'MIXED_ENVIRONMENT',\n]);\n\n/** Map an installer integration id to the framework name doctor's checks expect. */\nconst INTEGRATION_FRAMEWORK_NAME: Record<string, string> = {\n nextjs: 'Next.js',\n 'react-router': 'React Router',\n 'tanstack-start': 'TanStack Start',\n};\n\nexport interface SecurityCheckResult {\n /** All security-class findings for this install (errors + warnings). */\n findings: AuthPatternFinding[];\n /**\n * Error-severity findings that must block a successful install. Empty when the\n * install is secure; a non-empty list means install should not report success.\n */\n blocking: AuthPatternFinding[];\n}\n\n/**\n * Run the security subset of doctor's auth-pattern checks against an install\n * directory. Pure file inspection — no network — so it is safe to call both\n * inside the installer's self-correction loop and as the final pre-success gate.\n *\n * This closes the install-validate ↔ doctor gap: previously install could report\n * `success: true` while `workos doctor` immediately found a security hole,\n * because neither the retry loop nor `validateInstallation` ran these checks.\n */\nexport async function runInstallSecurityChecks(integration: string, installDir: string): Promise<SecurityCheckResult> {\n const framework: FrameworkInfo = {\n name: INTEGRATION_FRAMEWORK_NAME[integration] ?? null,\n version: null,\n };\n // checkAuthPatterns loads .env files itself; these structs only satisfy the\n // shape its non-Next.js checks read from.\n const environment: EnvironmentInfo = {\n apiKeyConfigured: false,\n apiKeyType: null,\n clientId: null,\n redirectUri: null,\n cookieDomain: null,\n baseUrl: null,\n };\n const sdk: SdkInfo = {\n name: null,\n version: null,\n latest: null,\n outdated: false,\n isAuthKit: false,\n language: 'javascript',\n };\n\n const result = await checkAuthPatterns({ installDir }, framework, environment, sdk);\n const findings = result.findings.filter((f) => SECURITY_FINDING_CODES.has(f.code));\n const blocking = findings.filter((f) => f.severity === 'error');\n return { findings, blocking };\n}\n\n/** Convert security findings into ValidationIssues for the emitter/report surfaces. */\nexport function securityFindingsToIssues(findings: AuthPatternFinding[]): ValidationIssue[] {\n return findings.map((f) => ({\n type: 'pattern',\n severity: f.severity,\n message: f.filePath ? `${f.message} (${f.filePath})` : f.message,\n hint: f.remediation,\n }));\n}\n\n/**\n * Build an agent correction prompt from security findings so the installer's\n * self-correction loop fixes them before declaring success. Returns an empty\n * string when there is nothing to correct.\n */\nexport function formatSecurityFindingsForAgent(findings: AuthPatternFinding[]): string {\n if (findings.length === 0) return '';\n const lines = findings.map((f) => {\n const loc = f.filePath ? ` in ${f.filePath}` : '';\n const fix = f.remediation ? ` Fix: ${f.remediation}` : '';\n return `- [${f.severity}] ${f.message}${loc}.${fix}`;\n });\n return `Security checks found issues that must be fixed:\\n\\n${lines.join('\\n')}\\n\\nApply the fixes above, then make sure the project still builds.`;\n}\n\n/**\n * Build the error message thrown when error-severity security findings survive\n * the installer's retries — the message that turns a silent insecure \"success\"\n * into a visible failure.\n */\nexport function formatBlockingSecurityError(blocking: AuthPatternFinding[]): string {\n const lines = blocking.map((f) => {\n const loc = f.filePath ? ` (${f.filePath})` : '';\n return ` • ${f.code}: ${f.message}${loc}`;\n });\n return [\n 'Installation produced insecure code that could not be auto-corrected:',\n '',\n ...lines,\n '',\n 'Fix the issues above (or run `workos doctor` for details and remediation) and re-run the installer.',\n ].join('\\n');\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workos",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "type": "module",
5
5
  "description": "The Official Workos CLI",
6
6
  "repository": {
@@ -54,7 +54,7 @@
54
54
  "@workos-inc/node": "^8.7.0",
55
55
  "@workos/migrations": "^2.0.0",
56
56
  "@workos/openapi-spec": "^0.1.0",
57
- "@workos/skills": "0.6.0",
57
+ "@workos/skills": "0.6.1",
58
58
  "chalk": "^5.6.2",
59
59
  "diff": "^8.0.3",
60
60
  "fast-glob": "^3.3.3",