diff --git a/src/content/docs/developer-tools/sdks/backend/tsr-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/tsr-sdk.mdx new file mode 100644 index 000000000..1fa1b7115 --- /dev/null +++ b/src/content/docs/developer-tools/sdks/backend/tsr-sdk.mdx @@ -0,0 +1,416 @@ +--- +page_id: 7eb15b27-864c-49fd-a12e-3f4d415f47fa +title: TanStack React Start SDK +description: "Install and configure the Kinde SDK for TanStack Start: environment variables, auth routes, middleware, route protection, and client hooks." +sidebar: + order: 10 +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - 7d311fcf-ca33-49ec-9286-419da4a91f41 + - 3747b2ea-82a0-4620-b71e-61a0622175e1 + - 3a5cbe42-d4c2-4f41-a243-a4852fdcf4a5 +head: + - tag: meta + attrs: + property: "og:image" + content: "https://kinde.com/assets/images/open-graph/DOCS-SSI-SDK_NEXT.png" +topics: + - developer-tools + - sdks + - tanstack + - backend +sdk: + - tanstack-start +languages: + - javascript + - typescript + - jsx + - tsx +audience: developers +complexity: intermediate +keywords: + - TanStack Start + - TanStack Router + - authentication + - route protection + - environment variables + - Vite +updated: 2026-04-07 +featured: false +deprecated: false +ai_summary: Install and configure the Kinde SDK for TanStack Start with auth handlers, global middleware, KindeTanstackProvider, useKindeAuth, server loaders, and protect utilities. +--- + +Official Kinde SDK for [TanStack Start](https://tanstack.com/start)—a full-stack React framework on [TanStack Router](https://tanstack.com/router). This guide covers a new or existing app on TanStack Start `v1.132.25` or higher (with `@tanstack/react-router` and `@tanstack/react-start`). + +### What you need + +- A [Kinde](https://app.kinde.com/) account (Sign up for free) +- [Node.js](https://nodejs.org/) version 20 or higher +- A TanStack Start project using `@tanstack/react-router` and `@tanstack/react-start` **v1.132.25** or higher + +## Quickstart + +### 1. Create a new TanStack Start project + +```bash +npx @tanstack/cli@latest create kinde-tanstack-app --yes +``` + +### 2. Create a Kinde app and set callback URLs + +1. In Kinde, select **Add new application**, select **Back-end application > Other back end** +2. Go to **View details** and copy the **Domain**, **Client ID** and **Client secret** values. +2. Add callback URLs, for example: + - **Allowed callback URLs** — `http://localhost:3000/api/auth/callback` + - **Allowed logout redirect URLs** — `http://localhost:3000` +3. Select **Save**. + +For production, add the same paths using your real domain. + +### 3. Install the Kinde SDK + + + +### 4. Add environment variables + +Put these in a `.env` file in the project root. Values come from **Details** page in Kinde. + +- **Client ID** → `VITE_KINDE_CLIENT_ID` +- **Client secret** → `KINDE_CLIENT_SECRET` +- **Domain** (issuer) → `VITE_KINDE_ISSUER_URL` +- **Site URL** (where the app runs) → `VITE_KINDE_SITE_URL` + + + +### 5. Add the Kinde auth route handler + +Create `src/routes/api.auth.$.ts`: + +```bash +touch "src/routes/api.auth.$/route.ts" +``` + +Add the following code: + +```tsx +import { kindeAuthHandler } from "@kinde/kinde-auth-tanstack-start/server" +import { createFileRoute } from "@tanstack/react-router" + +export const Route = createFileRoute("/api/auth/$")({ + server: { + handlers: { + GET: async ({ request }) => kindeAuthHandler(request), + POST: async ({ request }) => kindeAuthHandler(request), + }, + }, +}) +``` + +This exposes flows such as: + +- `/api/auth/login` +- `/api/auth/logout` +- `/api/auth/callback` +- `/api/auth/register` +- `/api/auth/create-org` + +### 6. Register global auth middleware + +Middleware protects the server, refreshes tokens, and powers route rules. It does **not** run in the browser, so client navigations still need [client-side protection](#how-do-i-protect-client-side-navigations). + + + +Create `start.ts` in the project root: + +```ts +import { createStart } from "@tanstack/react-start" +import { createKindeGlobalMiddleware } from "@kinde/kinde-auth-tanstack-start/server" + +export const startInstance = createStart(() => { + return { + requestMiddleware: [ + createKindeGlobalMiddleware({ + routeRules: [], + }), + ], + } +}) +``` + +**Route rules** control which paths require auth and optional checks (permissions, roles, feature flags, billing entitlements). Paths support globs, for example: + +- `/admin/*` — `/admin` and descendants +- `*/faq` — any route ending in `/faq` +- `/admin/*/settings` — nested segments + +Example: + +```ts +import { createStart } from "@tanstack/react-start" +import { createKindeGlobalMiddleware } from "@kinde/kinde-auth-tanstack-start/server" + +export const startInstance = createStart(() => { + return { + requestMiddleware: [ + createKindeGlobalMiddleware({ + routeRules: [ + { + path: "/dashboard/*", + redirectTo: "/", + }, + { + path: "/admin/*", + redirectTo: "/", + has: { + permissions: ["read:admin"], + roles: ["admin"], + }, + }, + { + path: "/pro/*", + redirectTo: "/", + has: { + billingEntitlements: ["pro"], + }, + }, + { + path: "*/new-wip-page", + redirectTo: "/current-page", + has: { + featureFlags: ["new-wip-page-access"], + }, + }, + ], + }), + ], + } +}) +``` + +### 7. Wrap the root route with `KindeTanstackProvider` + +In `src/routes/__root.tsx`, wrap the app so hooks and token refresh work: + +```tsx +import { + createRootRouteWithContext, + HeadContent, + Outlet, + Scripts, +} from "@tanstack/react-router" +import { KindeTanstackProvider } from "@kinde/kinde-auth-tanstack-start" + +export const Route = createRootRouteWithContext()({ + component: RootComponent, +}) + +function RootComponent() { + return ( + + + + + + + + + + + + ) +} +``` + +Add a router context type to `createRootRouteWithContext()` when your app needs typed context. + +### 8. Add auth UI components + +Use `useKindeAuth` plus link components from the SDK: + +```tsx +import { + useKindeAuth, + LoginLink, + LogoutLink, + RegisterLink, +} from "@kinde/kinde-auth-tanstack-start" + +function MyComponent() { + const { user, isAuthenticated, isLoading } = useKindeAuth() + + if (isLoading) { + return
Loading...
+ } + + return ( +
+ {isAuthenticated ? ( + <> +

Welcome, {user?.givenName}!

+ Log out + + ) : ( + <> + Sign in + Sign up + + )} +
+ ) +} +``` + +**Static redirect after login** — set `KINDE_POST_LOGIN_REDIRECT_URL` in `.env`. + +**Dynamic redirect** — pass `postLoginRedirectURL` on the link, or send users to `/api/auth/login?post_login_redirect_url=/dashboard`. + +## Display logged-in user information + +Use server helpers in a route `loader` (or other server code): + +```tsx +import { createFileRoute } from "@tanstack/react-router" +import { + getUserProfile, + isAuthenticated, +} from "@kinde/kinde-auth-tanstack-start/server" + +export const Route = createFileRoute("/dashboard")({ + component: Dashboard, + + loader: async () => { + const user = await getUserProfile() + const isAuthed = await isAuthenticated() + + return { user, isAuthed } + }, +}) + +function Dashboard() { + const { user } = Route.useLoaderData() + + return
Welcome, {user?.givenName}!
+} +``` + +## Protect routes with roles and permissions + +### Per-route middleware and `protect` + +Use `KindeAuthMiddleware` with `protect` and optional `has` checks: + +```tsx +import { createFileRoute } from "@tanstack/react-router" +import { + KindeAuthMiddleware, + protect, + getUserProfile, +} from "@kinde/kinde-auth-tanstack-start/server" + +export const Route = createFileRoute("/protected")({ + component: ProtectedPage, + + server: { + middleware: [KindeAuthMiddleware], + }, + + beforeLoad: () => + protect({ + has: { + permissions: ["read:protected"], + // roles: ["admin"], + // featureFlags: ["new-dashboard"], + // billingEntitlements: ["pro"], + }, + redirectTo: "/", + }), + + loader: async () => { + const user = await getUserProfile() + return { user } + }, +}) + +function ProtectedPage() { + const { user } = Route.useLoaderData() + + return
Protected content for {user?.givenName}
+} +``` + +`redirectTo` defaults to `KINDE_SITE_URL` if omitted. + +### Protect client-side navigations + +`protect` in `beforeLoad` should receive the route path so it can apply the same **route rules** as global middleware: + +```tsx +import { createFileRoute } from "@tanstack/react-router" +import { protect } from "@kinde/kinde-auth-tanstack-start/server" + +export const Route = createFileRoute("/protected/")({ + beforeLoad: async (ctx) => { + await protect(ctx.location.pathname) + }, +}) +``` + +Code after `protect` does not run if the user is redirected. + +## Changing the default `/api/auth` paths + +Set a custom base path in `.env`: + +```bash +KINDE_AUTH_API_PATH="/my/custom/path" +``` + +Optional overrides for sub-routes (defaults shown in parentheses): + +- `KINDE_AUTH_LOGIN_ROUTE` (`login`) +- `KINDE_AUTH_LOGOUT_ROUTE` (`logout`) +- `KINDE_AUTH_REGISTER_ROUTE` (`register`) +- `KINDE_AUTH_CREATE_ORG_ROUTE` (`create-org`) +- `KINDE_AUTH_HEALTH_ROUTE` (`health`) +- `KINDE_AUTH_SETUP_ROUTE` (`setup`) + +**Example:** If `KINDE_AUTH_API_PATH="/my/custom/path"` and `KINDE_AUTH_LOGIN_ROUTE="app_login"`, login is at `/my/custom/path/app_login`. Rename the route file to match your API path if you change it. + + + +## Debug mode + +Set in `.env`: + +```shell +KINDE_DEBUG_MODE=true +``` + +You will see extra logs in the console, useful when troubleshooting. + +## Deploy to production + +1. Set production values for all Kinde env vars. +2. Set `VITE_KINDE_SITE_URL` to your production origin. +3. In Kinde, add production **Allowed callback URLs** and **Allowed logout redirect URLs**, for example: + - `https://yourdomain.com/api/auth/callback` + - `https://yourdomain.com` + +## API Reference + +To be added. + +## Resources + +- [Kinde documentation](/) +- [TanStack Start](https://tanstack.com/start) +- [TanStack Router](https://tanstack.com/router) +- [SDK issues on GitHub](https://github.com/kinde-oss/kinde-auth-tsr/issues)