Basic Usage
Configuration and usage guide for Keylio
Server Configuration
Follow the steps below to configure Keylio in your project.
Keylio requires Session and Account models with specific fields to function correctly.
The User model is flexible — only the fields required for relations are mandatory.
You are free to extend the User model with additional fields based on your application needs.
Add the following models to your schema.prisma file.
SessionandAccountmodels must match the schema below exactly.- The
Usermodel may include additional fields, but the relation fields shown are required.
model User {
/// Required — used to link sessions and accounts
id String @id @default(uuid())
/// Required — used for credential authentication
email String @unique
password String?
/// Optional — add or remove freely
role String?
createdAt DateTime @default(now())
/// Required relations
sessions Session[]
accounts Account[]
@@map("users")
}
/// REQUIRED — do not modify field names or relations
model Session {
id String @id @default(cuid())
sessionToken String @unique @map("session_token")
userId String @map("user_id")
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("sessions")
}
/// REQUIRED — do not modify field names or relations
model Account {
id String @id @default(cuid())
userId String @map("user_id")
type String
provider String
providerAccountId String @map("provider_account_id")
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@map("accounts")
}You can safely rename table mappings (@@map) and add indexes,
but altering required fields or relations will break Keylio's adapters.
Create a reusable authentication file (for example, utils/auth.ts) to initialize Keylio.
Beta Notice: Currently, KeylioConfig only supports session and adapter. Other options will be available soon.
import { prisma } from "@/lib/prisma";
import { Keylio } from "keylio";
import { prismaAdapter } from "keylio/adapters/prisma";
import type { KeylioAuthConfig } from "keylio/types";
const authOptions: KeylioAuthConfig = {
adapter: prismaAdapter(prisma),
session: {
secret: process.env.AUTH_SECRET || "default_secret",
},
};
const keylio = new Keylio(authOptions);
export { authOptions, keylio };Define the required environment variable in your .env file.
AUTH_SECRET=your_secure_random_secretAlways use a strong, unpredictable secret in production environments.
Use the Next.js handler to connect Keylio to your route (for example, app/api/auth/[...keylio]/route.ts).
import { keylio } from "@/utils/auth";
import { KeylioNextHandler } from "keylio/next";
export const { GET, POST } = KeylioNextHandler(keylio);This exposes standardized authentication endpoints compatible with the Next.js App Router.
Client Configuration
To enable session management in your React components, you must wrap your application with the KeylioSessionProvider.
Since the provider uses React Context, it must be a Client Component. Create a wrapper if you are using Next.js App Router.
"use client";
import { KeylioSessionProvider } from "keylio/react";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<KeylioSessionProvider>
{children}
</KeylioSessionProvider>
);
}You can configure the provider with the following props:
| Prop | Type | Default | Description |
|---|---|---|---|
autoRefreshInterval | number | 300000 | Interval in milliseconds to refresh the session. |
refetchOnWindowFocus | boolean | true | Whether to update the session when the window gains focus. |
initialSession | SessionState | null | Initial session data (useful for SSR hydration). |
Import and use the providers in your root layout.
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}Using the Hook
The useSession hook provides access to the current user's session, authentication status, and helper methods.
"use client";
import { useSession } from "keylio/react";
export function Dashboard() {
const { data, status, signOut, refresh } = useSession();
if (status === "loading") {
return <p>Loading...</p>;
}
if (status === "unauthenticated") {
return <p>Access Denied</p>;
}
return (
<div>
<h1>Welcome back, {data?.user.email}</h1>
<button onClick={() => refresh()}>Refresh Session</button>
<button onClick={() => signOut()}>Sign Out</button>
</div>
);
}useSession must be used within a component wrapped by KeylioSessionProvider. If used outside, it will throw an error.
Authentication Actions
Keylio provides helper functions to handle sign-in and sign-up operations from your client components.
Sign In
Use the signIn function to authenticate users. It handles the API request to your Keylio backend.
"use client";
import { signIn } from "keylio/react";
import { useState } from "react";
import { useRouter } from "next/navigation";
export function SignIn() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const router = useRouter();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const result = await signIn({
type: "credentials",
data: { email, password },
});
console.log("Signed in:", result);
router.push("/dashboard");
} catch (error) {
console.error("Login failed", error);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign In</button>
</form>
);
}Sign Up
Similarly, use the signUp function to register new users.
"use client";
import { signUp } from "keylio/react";
import { useState } from "react";
export function SignUp() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const result = await signUp({
type: "credentials",
data: { email, password },
});
console.log("Account created:", result);
} catch (error) {
console.error("Registration failed", error);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign Up</button>
</form>
);
}