diff --git a/skills/workos-authkit-tanstack-start/SKILL.md b/skills/workos-authkit-tanstack-start/SKILL.md index c83ed2d..36356de 100644 --- a/skills/workos-authkit-tanstack-start/SKILL.md +++ b/skills/workos-authkit-tanstack-start/SKILL.md @@ -86,6 +86,8 @@ Default redirect URI: `http://localhost:3000/api/auth/callback` **authkitMiddleware MUST be configured or auth will fail silently.** +**WARNING: Do NOT add middleware to `createRouter()` in `router.tsx` or `app.tsx`. That is TanStack Router (client-side only). Server middleware belongs in `start.ts` using `requestMiddleware`.** + Create or update `src/start.ts` (or `app/start.ts` for legacy): ```typescript diff --git a/src/doctor/checks/auth-patterns.spec.ts b/src/doctor/checks/auth-patterns.spec.ts index 0226bda..0617360 100644 --- a/src/doctor/checks/auth-patterns.spec.ts +++ b/src/doctor/checks/auth-patterns.spec.ts @@ -368,7 +368,7 @@ describe('checkAuthPatterns', () => { expect(result.findings.find((f) => f.code === 'CALLBACK_ROUTE_MISSING')).toBeUndefined(); }); - it('no finding when callback route exists (TanStack Start flat)', async () => { + it('no finding when callback route exists (TanStack Start flat in src/)', async () => { writeFixtureFile( testDir, 'src/routes/auth.callback.tsx', @@ -382,6 +382,36 @@ describe('checkAuthPatterns', () => { ); expect(result.findings.find((f) => f.code === 'CALLBACK_ROUTE_MISSING')).toBeUndefined(); }); + + it('no finding when callback route exists (TanStack Start nested in src/)', async () => { + writeFixtureFile( + testDir, + 'src/routes/api/auth/callback.tsx', + 'export const Route = createFileRoute("/api/auth/callback")', + ); + const result = await checkAuthPatterns( + makeOptions(testDir), + makeFramework({ name: 'TanStack Start', version: '1.0.0', expectedCallbackPath: '/api/auth/callback' }), + makeEnv(), + makeSdk({ name: '@workos-inc/authkit-tanstack-start' }), + ); + expect(result.findings.find((f) => f.code === 'CALLBACK_ROUTE_MISSING')).toBeUndefined(); + }); + + it('no finding when callback route exists (TanStack Start flat in app/)', async () => { + writeFixtureFile( + testDir, + 'app/routes/api.auth.callback.tsx', + 'export const Route = createFileRoute("/api/auth/callback")', + ); + const result = await checkAuthPatterns( + makeOptions(testDir), + makeFramework({ name: 'TanStack Start', version: '1.0.0', expectedCallbackPath: '/api/auth/callback' }), + makeEnv(), + makeSdk({ name: '@workos-inc/authkit-tanstack-start' }), + ); + expect(result.findings.find((f) => f.code === 'CALLBACK_ROUTE_MISSING')).toBeUndefined(); + }); }); describe('API_KEY_LEAKED_TO_CLIENT', () => { @@ -514,7 +544,7 @@ describe('checkAuthPatterns', () => { describe('MISSING_AUTHKIT_MIDDLEWARE (TanStack Start)', () => { it('warning when start.ts lacks authkitMiddleware', async () => { - writeFixtureFile(testDir, 'src/start.ts', 'export default defineStart({})'); + writeFixtureFile(testDir, 'src/start.ts', 'export default createStart({})'); const result = await checkAuthPatterns( makeOptions(testDir), makeFramework({ name: 'TanStack Start', expectedCallbackPath: '/auth/callback' }), @@ -529,8 +559,9 @@ describe('checkAuthPatterns', () => { testDir, 'src/start.ts', ` + import { createStart } from "@tanstack/react-start"; import { authkitMiddleware } from "@workos-inc/authkit-tanstack-start"; - export default defineStart({ middleware: [authkitMiddleware()] }); + export default createStart({ requestMiddleware: [authkitMiddleware()] }); `, ); const result = await checkAuthPatterns( diff --git a/src/doctor/checks/auth-patterns.ts b/src/doctor/checks/auth-patterns.ts index 15af4a0..fbfd8f2 100644 --- a/src/doctor/checks/auth-patterns.ts +++ b/src/doctor/checks/auth-patterns.ts @@ -299,13 +299,16 @@ function checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] { possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`)); } } else if (ctx.framework.name === 'TanStack Start') { - // Modern flat: src/routes/api.auth.callback.tsx Legacy nested: app/routes/api/auth/callback.tsx + // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx + // Both conventions work in both src/ and app/ directories const segments = callbackPath.replace(/^\//, '').split('/'); const flat = segments.join('.'); const nested = segments.join('/'); - for (const ext of ['tsx', 'jsx', 'ts', 'js']) { - possiblePaths.push(join(ctx.installDir, 'src', 'routes', `${flat}.${ext}`)); - possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`)); + for (const prefix of ['src', 'app']) { + for (const ext of ['tsx', 'jsx', 'ts', 'js']) { + possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`)); + possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`)); + } } } @@ -423,7 +426,10 @@ function checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] severity: 'warning', message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it', filePath: relative(ctx.installDir, startFile), - remediation: 'Add authkitMiddleware to your start.ts server middleware configuration.', + remediation: + 'Add authkitMiddleware to requestMiddleware in src/start.ts:\n' + + ' import { authkitMiddleware } from "@workos/authkit-tanstack-react-start";\n' + + ' export default createStart({ requestMiddleware: [authkitMiddleware()] });', }, ]; }