Skip to content
Closed
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
83 changes: 83 additions & 0 deletions examples/react/start-basic-ory/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
.vite
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
node_modules
package-lock.json
yarn.lock

# builds
types
build
*/build
dist
.output
lib
es
artifacts
.rpt2_cache
coverage
*.tgz
.wrangler

# tests
packages/router-generator/tests/**/*.gen.ts
packages/router-generator/tests/**/*.gen.js
**/port*.txt

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
.next

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.history
size-plugin.json
stats-hydration.json
stats-react.json
stats.html
.vscode/settings.json

*.log
.DS_Store
.cache
.pnpm-store
ts-perf

/examples/*/*/yarn.lock
/examples/*/*/package-lock.json

.netlify

nx-cloud.env
.nx/cache
.nx/workspace-data

gpt/db.json

vite.config.timestamp-*
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

vite.config.timestamp_*
vite.config.js.timestamp_*
vite.config.ts.timestamp_*

.idea
*.vitest-temp.json

# Handling VSCode settings
/.vscode/
!/examples/react/**/.vscode/settings.json

**/llms

**/.tanstack

CLAUDE.md
108 changes: 108 additions & 0 deletions examples/react/start-basic-ory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# TanStack Start - Ory Auth Example

A TanStack Start example demonstrating authentication with [Ory Kratos](https://www.ory.com/docs/kratos/quickstart).
Routes are guarded via route context, and all Ory API calls are made through server functions using the
[`@ory/client-fetch`](https://github.com/ory/sdk) SDK.

- [TanStack Router Docs](https://tanstack.com/router)
- [Ory Kratos Docs](https://www.ory.com/docs/kratos/quickstart)
- [Ory SDK (client-fetch)](https://github.com/ory/sdk)

## Start a new project based on this example

```sh
npx gitpick TanStack/router/tree/main/examples/react/start-basic-ory start-basic-ory
```

## Prerequisites

- [Node.js](https://nodejs.org) 20+
- [pnpm](https://pnpm.io)
- An Ory identity provider running and accessible. See the two options below.

## Option A — Ory Network + Ory Tunnel (recommended for new projects)

Ory Tunnel proxies Ory Network (cloud) APIs onto `localhost:4000`, which is the same origin the app expects.
This avoids CORS and cookie-domain issues without running anything in Docker.

1. Install the Ory CLI:

```sh
npm install -g @ory/ory-cli
```

2. Log in and create a project (skip if you already have one):

```sh
ory login
ory create project --name "my-ory-project"
```

Note the **project ID** and **workspace ID** that are printed.

3. Start the tunnel. It exposes Ory APIs at `http://localhost:4000` by default,
which matches the `VITE_ORY_SDK_URL` default in this example:

```sh
ory tunnel --project <project-id> --workspace <workspace-id> http://localhost:3000
```

Keep this process running in a separate terminal while you develop.

4. In another terminal, start the app (see [Getting Started](#getting-started) below).
Access it through the tunnel URL (`http://localhost:4000`) rather than `http://localhost:3000`
so that cookies and CSRF tokens share the same domain.

## Option B — Self-hosted Kratos in Docker

Use this option if you want a fully local setup with no cloud dependency.

1. Clone the Kratos repo and run the standalone quickstart:

```sh
git clone --depth 1 https://github.com/ory/kratos.git
cd kratos
docker-compose -f quickstart.yml -f quickstart-standalone.yml up --force-recreate
```

This starts:
- Kratos public API on `http://localhost:4433`
- Kratos admin API on `http://localhost:4434`
- The Ory self-service UI on `http://localhost:4455`

2. Set `VITE_ORY_SDK_URL` to point at the Kratos public API:

```sh
export VITE_ORY_SDK_URL=http://localhost:4433
```

3. Start the app (see [Getting Started](#getting-started) below).

> **Note:** In standalone mode the self-service UI (`localhost:4455`) handles login and
> registration pages. Your app's Login link will redirect there. Cookie domains work
> because everything runs on `127.0.0.1`.

## Getting Started

From your terminal:

```sh
pnpm install
pnpm dev
```

This starts the app in development mode on `http://localhost:3000`, rebuilding assets on file changes.

## Build

To build the app for production:

```sh
pnpm build
```

To preview the production build locally:

```sh
pnpm preview
```
30 changes: 30 additions & 0 deletions examples/react/start-basic-ory/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "tanstack-start-example-bare",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build && tsc --noEmit",
"preview": "vite preview",
"start": "pnpx srvx --prod -s ../client dist/server/server.js"
},
"dependencies": {
"@ory/client-fetch": "^1.22.22",
"@tanstack/react-router": "^1.158.0",
"@tanstack/react-router-devtools": "^1.158.0",
"@tanstack/react-start": "^1.158.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"zod": "^3.24.2"
},
"devDependencies": {
"@types/node": "^22.5.4",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"@vitejs/plugin-react": "^4.3.4",
"typescript": "^5.7.2",
"vite": "^7.3.1",
"vite-tsconfig-paths": "^5.1.4"
}
}
Binary file not shown.
Binary file added examples/react/start-basic-ory/public/ory.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 111 additions & 0 deletions examples/react/start-basic-ory/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* 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 AuthenticatedRouteImport } from './routes/_authenticated'
import { Route as IndexRouteImport } from './routes/index'
import { Route as AuthenticatedProfileRouteImport } from './routes/_authenticated/profile'

const AuthenticatedRoute = AuthenticatedRouteImport.update({
id: '/_authenticated',
getParentRoute: () => rootRouteImport,
} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRouteImport,
} as any)
const AuthenticatedProfileRoute = AuthenticatedProfileRouteImport.update({
id: '/profile',
path: '/profile',
getParentRoute: () => AuthenticatedRoute,
} as any)

export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/profile': typeof AuthenticatedProfileRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/profile': typeof AuthenticatedProfileRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
'/_authenticated': typeof AuthenticatedRouteWithChildren
'/_authenticated/profile': typeof AuthenticatedProfileRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/profile'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/profile'
id: '__root__' | '/' | '/_authenticated' | '/_authenticated/profile'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
AuthenticatedRoute: typeof AuthenticatedRouteWithChildren
}

declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/_authenticated': {
id: '/_authenticated'
path: ''
fullPath: '/'
preLoaderRoute: typeof AuthenticatedRouteImport
parentRoute: typeof rootRouteImport
}
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexRouteImport
parentRoute: typeof rootRouteImport
}
'/_authenticated/profile': {
id: '/_authenticated/profile'
path: '/profile'
fullPath: '/profile'
preLoaderRoute: typeof AuthenticatedProfileRouteImport
parentRoute: typeof AuthenticatedRoute
}
}
}

interface AuthenticatedRouteChildren {
AuthenticatedProfileRoute: typeof AuthenticatedProfileRoute
}

const AuthenticatedRouteChildren: AuthenticatedRouteChildren = {
AuthenticatedProfileRoute: AuthenticatedProfileRoute,
}

const AuthenticatedRouteWithChildren = AuthenticatedRoute._addFileChildren(
AuthenticatedRouteChildren,
)

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
AuthenticatedRoute: AuthenticatedRouteWithChildren,
}
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>>
}
}
20 changes: 20 additions & 0 deletions examples/react/start-basic-ory/src/router.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

export function getRouter() {
const router = createRouter({
routeTree,
defaultPreload: 'intent',
defaultErrorComponent: (err) => <p>{err.error.stack}</p>,
defaultNotFoundComponent: () => <p>not found</p>,
scrollRestoration: true,
})

return router
}

declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof getRouter>
}
}
Loading