npx create-remix@latest
npm i @kinde-oss/kinde-auth-remix-sdk
Values for environment variables can be found in your Kinde app under “Application Details”.
// .env
KINDE_CLIENT_ID=<your-client-id> (found in Kinde app)
KINDE_CLIENT_SECRET=<your-client-secret> (found in Kinde app)
KINDE_ISSUER_URL=https://<your-kinde-subdomain>.kinde.com (found in Kinde app)
KINDE_SITE_URL=http://localhost:3000
KINDE_POST_LOGOUT_REDIRECT_URL=http://localhost:3000
KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000
SESSION_SECRET=<your-secret>
Create file app/routes/kinde-auth.$index.tsx
import { handleAuth } from "@kinde-oss/kinde-auth-remix-sdk";
import { LoaderFunctionArgs } from "@remix-run/node";
export async function loader({ params, request }: LoaderFunctionArgs) {
return await handleAuth(request, params.index);
}
Authenticate users by redirecting them to /kinde-auth/login
, /kinde-auth/register
and /kinde-auth/logout
with RemixLinks
.
Use getKindeSession
inside the Remix loader
to get the user data from Kinde.
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { getKindeSession } from "@kinde-oss/kinde-auth-remix-sdk";
import { Link, useLoaderData } from "@remix-run/react";
import { json } from "@remix-run/node";
export const meta: MetaFunction = () => {
return [
{ title: "New Remix App" },
{ name: "description", content: "Welcome to Remix!" },
];
};
export const loader = async ({ request }: LoaderFunctionArgs) => {
const { getUser } = await getKindeSession(request);
const user = await getUser();
return json({ user });
};
export default function Index() {
const data = useLoaderData<{ user: KindeUser }>();
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
<h1>Welcome to Remix (with Kinde)</h1>
{data.user ? (
<>
<Link to={"/kinde-auth/logout"}>
<button>Logout</button>
</Link>
<code>
<pre>{JSON.stringify(data.user, null, 2)}</pre>
</code>
</>
) : (
<>
<Link to={"/kinde-auth/login"}>
<button>Login</button>
</Link>
<Link to={"/kinde-auth/register"}>
<button>Register</button>
</Link>
</>
)}
</div>
);
}
In the loader
, you can check if the user exists and then handle route protection there.
In this example I redirect the user to login if there is no logged in data.
export const loader = async ({ request }: LoaderFunctionArgs) => {
const { user } = await getKindeSession(request);
if (user === null) {
throw redirect("/kinde-auth/login");
}
return json({ user });
};