Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docs/start/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@
"label": "Material UI",
"to": "framework/react/examples/start-material-ui"
},
{
"label": "Basic + Auth.js",
"to": "framework/solid/examples/start-basic-authjs"
},
Comment on lines +304 to +307
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

React “Basic + Auth.js” example likely points to the wrong route

This React example entry uses a Solid docs path:

{
  "label": "Basic + Auth.js",
  "to": "framework/solid/examples/start-basic-authjs"
}

If there is a dedicated React example page, this should probably be:

- "to": "framework/solid/examples/start-basic-authjs"
+ "to": "framework/react/examples/start-basic-authjs"

Otherwise, readers clicking the React example will land in the Solid section.

🤖 Prompt for AI Agents
In docs/start/config.json around lines 304 to 307, the nav entry labeled "Basic
+ Auth.js" currently points to the Solid examples path; update the "to" value to
the correct React examples route (e.g.
"framework/react/examples/start-basic-authjs") if a React example exists,
otherwise create or move the example under the React docs and/or add a redirect
so the link resolves to the intended React page.

{
"label": "Basic + Static rendering",
"to": "framework/react/examples/start-basic-static"
Expand Down Expand Up @@ -331,9 +335,13 @@
"to": "framework/solid/examples/start-supabase-basic"
},
{
"label": "Bare + Convex + Better Auth",
"label": "Basic + Convex + Better Auth",
"to": "framework/solid/examples/start-convex-better-auth"
},
{
"label": "Basic + Auth.js",
"to": "framework/solid/examples/start-basic-authjs"
},
{
"label": "Basic + Static rendering",
"to": "framework/solid/examples/start-basic-static"
Expand Down
1 change: 1 addition & 0 deletions docs/start/framework/react/guide/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ You have several options for authentication in your TanStack Start application:
1. **[Clerk](https://clerk.dev)** - Complete authentication platform with UI components
2. **[WorkOS](https://workos.com)** - Enterprise-focused with SSO and compliance features
3. **[Better Auth](https://www.better-auth.com/)** - Open-source TypeScript library
4. **[Auth.js](https://authjs.dev/)** - Open-source library supporting 80+ OAuth providers

**DIY Implementation Benefits:**

Expand Down
1 change: 1 addition & 0 deletions docs/start/framework/solid/guide/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ You have several options for authentication in your TanStack Start application:
1. **[Clerk](https://clerk.dev)** - Complete authentication platform with UI components
2. **[WorkOS](https://workos.com)** - Enterprise-focused with SSO and compliance features
3. **[Better Auth](https://www.better-auth.com/)** - Open-source TypeScript library
4. **[Auth.js](https://authjs.dev/)** - Open-source library supporting 80+ OAuth providers

**DIY Implementation Benefits:**

Expand Down
11 changes: 11 additions & 0 deletions examples/react/start-basic-authjs/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Auth.js Configuration
AUTH_SECRET=your-secret-key-here-min-32-chars-long

# Auth.js URL (must include the auth path)
AUTH_URL=http://localhost:10000/api/auth

# Auth0 Configuration (https://manage.auth0.com)
# Auth.js auto-reads these env vars for the Auth0 provider
AUTH_AUTH0_ID=your-auth0-client-id
AUTH_AUTH0_SECRET=your-auth0-client-secret
AUTH_AUTH0_ISSUER=https://your-tenant.auth0.com
6 changes: 6 additions & 0 deletions examples/react/start-basic-authjs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
dist
.env
*.local
.DS_Store
.tanstack
34 changes: 34 additions & 0 deletions examples/react/start-basic-authjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "tanstack-router-react-example-basic-authjs",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"start": "pnpx srvx --prod -s ../client dist/server/server.js"
},
"dependencies": {
"@auth/core": "^0.41.1",
"@tanstack/react-router": "^1.139.3",
"@tanstack/react-router-devtools": "^1.139.3",
"@tanstack/react-start": "^1.139.3",
"start-authjs": "^1.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^2.6.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.15",
"@types/node": "^22.5.4",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"postcss": "^8.5.1",
"tailwindcss": "^4.1.15",
"typescript": "^5.7.2",
"vite": "^7.1.7",
"@vitejs/plugin-react": "^4.6.0",
"vite-tsconfig-paths": "^5.1.4"
}
}
5 changes: 5 additions & 0 deletions examples/react/start-basic-authjs/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
plugins: {
'@tailwindcss/postcss': {},
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
ErrorComponent,
Link,
rootRouteId,
useMatch,
useRouter,
} from '@tanstack/react-router'
import type { ErrorComponentProps } from '@tanstack/react-router'

export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
const router = useRouter()
const isRoot = useMatch({
strict: false,
select: (state) => state.id === rootRouteId,
})

console.error('DefaultCatchBoundary Error:', error)

return (
<div className="min-w-0 flex-1 p-4 flex flex-col items-center justify-center gap-6">
<ErrorComponent error={error} />
<div className="flex gap-2 items-center flex-wrap">
<button
onClick={() => {
router.invalidate()
}}
className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded-sm text-white uppercase font-extrabold`}
>
Try Again
</button>
{isRoot ? (
<Link
to="/"
className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded-sm text-white uppercase font-extrabold`}
>
Home
</Link>
) : (
<Link
to="/"
className={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded-sm text-white uppercase font-extrabold`}
onClick={(e) => {
e.preventDefault()
window.history.back()
}}
>
Go Back
</Link>
)}
</div>
</div>
)
}
25 changes: 25 additions & 0 deletions examples/react/start-basic-authjs/src/components/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Link } from '@tanstack/react-router'

export function NotFound({ children }: { children?: any }) {
return (
<div className="space-y-2 p-2">
<div className="text-gray-600 dark:text-gray-400">
{children || <p>The page you are looking for does not exist.</p>}
</div>
<p className="flex items-center gap-2 flex-wrap">
<button
onClick={() => window.history.back()}
className="bg-emerald-500 text-white px-2 py-1 rounded-sm uppercase font-black text-sm"
>
Go back
</button>
<Link
to="/"
className="bg-cyan-600 text-white px-2 py-1 rounded-sm uppercase font-black text-sm"
>
Start Over
</Link>
</p>
</div>
)
}
122 changes: 122 additions & 0 deletions examples/react/start-basic-authjs/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* eslint-disable */

// @ts-nocheck

// noinspection JSUnusedGlobalSymbols

// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.

import { Route as rootRouteImport } from './routes/__root'
import { Route as ProtectedRouteImport } from './routes/protected'
import { Route as LoginRouteImport } from './routes/login'
import { Route as IndexRouteImport } from './routes/index'
import { Route as ApiAuthSplatRouteImport } from './routes/api/auth/$'

const ProtectedRoute = ProtectedRouteImport.update({
id: '/protected',
path: '/protected',
getParentRoute: () => rootRouteImport,
} as any)
const LoginRoute = LoginRouteImport.update({
id: '/login',
path: '/login',
getParentRoute: () => rootRouteImport,
} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRouteImport,
} as any)
const ApiAuthSplatRoute = ApiAuthSplatRouteImport.update({
id: '/api/auth/$',
path: '/api/auth/$',
getParentRoute: () => rootRouteImport,
} as any)

export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/protected': typeof ProtectedRoute
'/api/auth/$': typeof ApiAuthSplatRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/protected': typeof ProtectedRoute
'/api/auth/$': typeof ApiAuthSplatRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/login': typeof LoginRoute
'/protected': typeof ProtectedRoute
'/api/auth/$': typeof ApiAuthSplatRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/login' | '/protected' | '/api/auth/$'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/login' | '/protected' | '/api/auth/$'
id: '__root__' | '/' | '/login' | '/protected' | '/api/auth/$'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
LoginRoute: typeof LoginRoute
ProtectedRoute: typeof ProtectedRoute
ApiAuthSplatRoute: typeof ApiAuthSplatRoute
}

declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/protected': {
id: '/protected'
path: '/protected'
fullPath: '/protected'
preLoaderRoute: typeof ProtectedRouteImport
parentRoute: typeof rootRouteImport
}
'/login': {
id: '/login'
path: '/login'
fullPath: '/login'
preLoaderRoute: typeof LoginRouteImport
parentRoute: typeof rootRouteImport
}
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexRouteImport
parentRoute: typeof rootRouteImport
}
'/api/auth/$': {
id: '/api/auth/$'
path: '/api/auth/$'
fullPath: '/api/auth/$'
preLoaderRoute: typeof ApiAuthSplatRouteImport
parentRoute: typeof rootRouteImport
}
}
}

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
LoginRoute: LoginRoute,
ProtectedRoute: ProtectedRoute,
ApiAuthSplatRoute: ApiAuthSplatRoute,
}
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()

import type { getRouter } from './router.tsx'
import type { createStart } from '@tanstack/react-start'
declare module '@tanstack/react-start' {
interface Register {
ssr: true
router: Awaited<ReturnType<typeof getRouter>>
}
}
15 changes: 15 additions & 0 deletions examples/react/start-basic-authjs/src/router.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
import { DefaultCatchBoundary } from './components/DefaultCatchBoundary'
import { NotFound } from './components/NotFound'

export function getRouter() {
const router = createRouter({
routeTree,
defaultPreload: 'intent',
defaultErrorComponent: DefaultCatchBoundary,
defaultNotFoundComponent: () => <NotFound />,
scrollRestoration: true,
})
return router
}
Loading
Loading