Keylio

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.

Important
  • Session and Account models must match the schema below exactly.
  • The User model may include additional fields, but the relation fields shown are required.
prisma/schema.prisma
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.

Auth Config Reference.

Beta Notice: Currently, KeylioConfig only supports session and adapter. Other options will be available soon.

utils/auth.ts
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.

.env
AUTH_SECRET=your_secure_random_secret

Always 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).

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.

app/providers.tsx
"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:

PropTypeDefaultDescription
autoRefreshIntervalnumber300000Interval in milliseconds to refresh the session.
refetchOnWindowFocusbooleantrueWhether to update the session when the window gains focus.
initialSessionSessionStatenullInitial session data (useful for SSR hydration).

Import and use the providers in your root layout.

app/layout.tsx
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.

components/dashboard.tsx
"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.

components/sign-in.tsx
"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.

components/sign-up.tsx
"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>
  );
}

On this page