Remix quickstart
Remix. Loaders. Actions.
Works with the web standards Remix already uses. Loaders get sessions, actions mint tokens, nothing leaks into components that do not need it.
Install
Install the core library and the Remix adapter in one step.
pnpm add kavachos @kavachos/remixConfigure the auth module
Remix runs on any fetch-capable runtime, so the Remix adapter is a thin wrapper over the core.
import { createAuth } from "kavachos";
import { remixAdapter } from "@kavachos/remix";
import { postgresAdapter } from "kavachos/adapters/postgres";
import { db } from "./db.server";
export const auth = remixAdapter(
createAuth({
secret: process.env.KAVACHOS_SECRET!,
baseUrl: process.env.APP_URL!,
database: postgresAdapter(db),
providers: [
{ id: "github", clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! },
],
})
);Mount the auth route
A single splat route handles every callback, sign-in, and sign-out URL.
import { auth } from "~/auth.server";
import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node";
export async function loader({ request, params }: LoaderFunctionArgs) {
return auth.handle(request, params.action!);
}
export async function action({ request, params }: ActionFunctionArgs) {
return auth.handle(request, params.action!);
}Guard a loader
Call auth.require() from any loader to redirect anonymous visitors and type the session.
import { auth } from "~/auth.server";
import type { LoaderFunctionArgs } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
export async function loader({ request }: LoaderFunctionArgs) {
const session = await auth.require(request);
return { name: session.user.name };
}
export default function Dashboard() {
const { name } = useLoaderData<typeof loader>();
return <h1>Hello, {name}</h1>;
}Mint an agent token
In a Remix action, take the current session and create a scoped agent delegation.
import { auth } from "~/auth.server";
import type { ActionFunctionArgs } from "@remix-run/node";
export async function action({ request }: ActionFunctionArgs) {
const session = await auth.require(request);
const agent = await auth.agents.create({
parent: session.subject.id,
name: "research.assistant",
scopes: ["tools:call:search"],
ttl: "15m",
});
const token = await auth.agents.issueToken(agent.id, {
audience: "https://your.mcp.server",
});
return Response.json({ token });
}What is next
You have a working flow. Now pick the next layer based on what you are building: agent identity, MCP OAuth, SCIM, or enterprise SSO.
- · Full identity model. Read concepts.
- · Agent delegation. AI agents guide.
- · MCP tool servers. MCP OAuth 2.1 guide.