hylekit
v1.0.7
Published
Distributed BetterAuth library for SvelteKit and Next.js with Google OAuth and Turso
Maintainers
Readme
HyleKit
Distributed BetterAuth library for SvelteKit and Next.js with Google OAuth and Turso cloud database.
Note: HyleKit provides only the authentication database. You will need to provision your own separate database for storing application data.
Features
- 🔐 Google OAuth - Simple Google login integration
- 🌐 Distributed Auth - Each app runs auth locally, sharing a centralized Turso auth database
- 📦 Framework Adapters - First-class support for SvelteKit and Next.js
- 🗄️ Turso/LibSQL - Edge-friendly SQLite database for auth
- 🔄 Session Management - Automatic session handling with cookies
- 🚀 BFF Pattern - Built-in support for Backend-For-Frontend architecture with Express
Database Architecture
HyleKit uses a centralized authentication database that all your applications connect to. This database stores:
- User accounts
- Sessions
- OAuth tokens
- Verification tokens
You must provision two databases:
| Database | Purpose | Provided by | |----------|---------|-------------| | Hyle Auth Database | Stores users, sessions, and auth data | HyleKit (shared Turso instance) | | Your Application Database | Stores your app's business data | You (separate database) |
┌─────────────────────────────────────────────────────────────────┐
│ Your Application │
├──────────────────────────────┬──────────────────────────────────┤
│ Hyle Auth Database │ Your Application Database │
│ (Turso - provided by Hyle) │ (Postgres, MySQL, SQLite, etc.) │
│ ├── users │ ├── products │
│ ├── sessions │ ├── orders │
│ ├── accounts │ ├── posts │
│ └── verification │ └── ... your data │
└──────────────────────────────┴──────────────────────────────────┘Important: Your application database can use any database technology you prefer. HyleKit does not manage or interact with your application data—only authentication.
Installation
npm install hylekitConfiguration
HyleKit uses a factory pattern - you pass configuration from your environment at initialization time. This design:
- ✅ Keeps secrets out of client bundles
- ✅ Throws runtime errors if factories are called on the client
- ✅ Gives you full control over configuration
Required Environment Variables
# Turso Database
HYLE_DATABASE_URL=libsql://[db-name]-[org].turso.io
HYLE_DATABASE_AUTH_TOKEN=your-turso-token
# BetterAuth
BETTER_AUTH_URL=http://localhost:5173 # Your app's URL
BETTER_AUTH_SECRET=your-random-secret
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secretQuick Start (Recommended)
The simplest way to set up HyleKit is with the unified createHyleKit function. It automatically reads configuration from your environment variables:
// lib/auth.ts (server-side only!)
import { connectHylekit } from "hylekit";
// Next.js (automatically reads process.env)
export const { handler, getSession, isAuthenticated, getUser, makeAuthenticatedCall } = connectHylekit.nextJs();
// OR for SvelteKit (must pass env object explicitly)
// import { env } from "$env/dynamic/private";
// export const { handler, getSession, ... } = connectHylekit.svelteKit(env);
Then create your auth route handler:
// app/api/auth/[...auth]/route.ts (Next.js)
import { handler } from "@/lib/auth";
export const { GET, POST } = handler;That's it! You now have authentication working.
Configuration
HyleKit looks for these environment variables by default:
# Database
HYLE_DATABASE_URL=...
HYLE_DATABASE_AUTH_TOKEN=...
# Auth
BETTER_AUTH_URL=...
BETTER_AUTH_SECRET=...
# Providers (Optional)
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...To override any of these defaults, simply pass the config object to the connect function:
// Next.js
connectHylekit.nextJs({
database: { url: "custom-url" }
});
// SvelteKit
connectHylekit.svelteKit(env, {
database: { url: "custom-url" }
});
Advanced Setup (Granular Control)
If you need more control, you can use the individual factory functions:
// lib/auth.ts (server-side only!)
import { createDb, createAuth } from "hylekit";
export const db = createDb({
url: process.env.HYLE_DATABASE_URL!,
authToken: process.env.HYLE_DATABASE_AUTH_TOKEN,
});
export const auth = createAuth(db, {
baseURL: process.env.BETTER_AUTH_URL!,
secret: process.env.BETTER_AUTH_SECRET!,
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
},
});⚠️ Security:
createDbandcreateAuthwill throw errors if called on the client side to prevent accidental secret exposure.
Architecture
HyleKit supports a BFF (Backend-For-Frontend) architecture:
┌─────────────────────────────────────────────────────────────────┐
│ Browser (Client FE) │
│ └── Uses: hyle (from "hylekit/client") │
└─────────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Next.js / SvelteKit Backend (BFF) │
│ ├── Auth: hyle.server (getSession, handler, etc.) │
│ └── Calls Express via: hyle.bff (BffClient) │
│ └── Attaches session as x-hyle-user/x-hyle-session headers │
└─────────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Express Backend │
│ └── Uses: hyle.server.express.middleware() │
│ └── Parses headers → req.authUser, req.authSession │
│ └── Optional: DB verification for service-to-service calls │
└─────────────────────────────────────────────────────────────────┘SvelteKit Setup
1. Create Server Auth Module
Create your auth instance in a server-only module:
// src/lib/server/auth.ts
import { connectHylekit } from "hylekit";
import { env } from "$env/dynamic/private";
export const { handler, getSession, isAuthenticated, createHandle, makeAuthenticatedCall } = connectHylekit.svelteKit(env);
2. Create Auth Route Handler
// src/routes/api/auth/[...auth]/+server.ts
import { handler } from "$lib/server/auth";
export const { GET, POST } = handler;3. Add Session Hook
// src/hooks.server.ts
import { createHandle } from "$lib/server/auth";
export const handle = createHandle();4. Extend App.Locals Types
// src/app.d.ts
import type { SessionResult, UserInfo } from "hylekit";
declare global {
namespace App {
interface Locals {
session: SessionResult;
user: UserInfo | null;
}
}
}
export {};5. Use in Pages
// src/routes/+page.server.ts
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async ({ locals }) => {
return { user: locals.user };
};<!-- src/routes/+page.svelte -->
<script lang="ts">
export let data;
</script>
{#if data.user}
<p>Welcome, {data.user.name}!</p>
<a href="/api/auth/sign-out">Sign out</a>
{:else}
<a href="/api/auth/sign-in/google">Sign in with Google</a>
{/if}Next.js Setup (App Router)
1. Create Server Auth Module
// lib/auth.ts (server-side only!)
import { connectHylekit } from "hylekit";
export const { handler, getSession, isAuthenticated, getUser, makeAuthenticatedCall } = connectHylekit.nextJs();
2. Create Auth Route Handler
// app/api/auth/[...auth]/route.ts
import { handler } from "@/lib/auth";
export const { GET, POST } = handler;3. Use in Server Components
// app/page.tsx
import { getSession } from "@/lib/auth";
export default async function Page() {
const session = await getSession();
if (!session) {
return <a href="/api/auth/sign-in/google">Sign in with Google</a>;
}
return (
<div>
<p>Welcome, {session.user.name}!</p>
<a href="/api/auth/sign-out">Sign out</a>
</div>
);
}4. Protected Routes
// app/dashboard/page.tsx
import { isAuthenticated, getUser } from "@/lib/auth";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
if (!(await isAuthenticated())) {
redirect("/api/auth/sign-in/google");
}
const user = await getUser();
return <p>Dashboard for {user?.name}</p>;
}BFF Pattern with Express
1. Setup Express Middleware
// express-app/src/app.ts
import express from "express";
import { createDb, createExpressMiddleware } from "hylekit";
const app = express();
// Option 1: Trust headers from BFF (no DB needed)
app.use(createExpressMiddleware()({
unauthenticatedRoutes: ["/health", "/public/*"],
}));
// Option 2: Verify sessions against DB (for service-to-service calls)
const db = createDb({
url: process.env.HYLE_DATABASE_URL!,
authToken: process.env.HYLE_DATABASE_AUTH_TOKEN,
});
app.use(createExpressMiddleware(db)({
unauthenticatedRoutes: ["/health", "/public/*"],
verifySession: true, // Checks session in Turso DB
}));2. Access Auth Context in Routes
Use req.authUser and req.authSession in your route handlers:
import type { AuthenticatedRequest } from "hylekit";
app.get("/api/profile", (req: AuthenticatedRequest, res) => {
// authUser is always available on authenticated routes
res.json({
userId: req.authUser.id,
email: req.authUser.email,
name: req.authUser.name,
});
});
app.post("/api/settings", (req: AuthenticatedRequest, res) => {
// Access full session data
console.log("Session expires:", req.authSession.expiresAt);
// Your business logic here
res.json({ success: true });
});3. Using Helper Functions
import { isAuthenticated, getAuthContext } from "hylekit";
// Type guard for optional auth routes
app.get("/api/greeting", (req, res) => {
if (isAuthenticated(req)) {
res.json({ message: `Hello, ${req.authUser.name}!` });
} else {
res.json({ message: "Hello, guest!" });
}
});
// Get auth context with error handling
app.post("/api/order", (req, res) => {
try {
const { user, session } = getAuthContext(req);
// Proceed with authenticated user
} catch (e) {
res.status(401).json({ error: "Not authenticated" });
}
});4. Call Express from Next.js/SvelteKit
Use the BFF client to make authenticated calls from your frontend backend:
// Next.js: lib/bff.ts
import { createNextJsBff } from "hylekit";
import { auth } from "./auth"; // Your auth instance from step 1
export const bff = createNextJsBff(auth, process.env.EXPRESS_API_URL!);
// Usage in app/api/data/route.ts
import { bff } from "@/lib/bff";
export async function GET() {
const data = await bff.get("/api/profile");
return Response.json(data);
}// SvelteKit: src/routes/api/data/+server.ts
import { createSvelteKitBff } from "hylekit";
import type { RequestHandler } from "./$types";
const bff = createSvelteKitBff(process.env.EXPRESS_API_URL!);
export const GET: RequestHandler = async (event) => {
// Use .with(event) to bind the request context
const data = await bff.with(event).get("/api/profile");
return new Response(JSON.stringify(data));
};Middleware Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| unauthenticatedRoutes | string[] | [] | Routes that skip authentication |
| verifySession | boolean | false | Verify session against DB (for service-to-service) |
| required | boolean | true | Return 401 for unauthenticated requests |
Route Pattern Examples
unauthenticatedRoutes: [
"/health", // Exact match
"/public/*", // Matches /public/anything (single level)
"/api/webhooks/**", // Matches /api/webhooks/a/b/c (deep)
]Database Schema
HyleKit uses Drizzle ORM. You can import the schema definitions for use with Drizzle Kit or migration tools.
// Import all schema definitions
import hyle from "hylekit";
const { user, session, account, verification } = hyle.schema;API Reference
The library exports a default hyle object containing:
hyle.server (Server-Only)
hylekit/sveltekit
handler:{ GET, POST }route handlers.createHandle(): Creates a SvelteKit handle hook.getSession(event): Get session from request event.isAuthenticated(event): Check if user is authenticated.makeAuthenticatedCall(fn): Wrapper to ensure authentication.
hylekit/nextjs
handler:{ GET, POST }route handlers.getSession(): Get session from current request headers.isAuthenticated(): Check if user is authenticated.getUser(): Get current user object.makeAuthenticatedCall(fn): Wrapper to ensure authentication.
hylekit/server/express (or hylekit)
middleware(options): Express middleware for session verification.isAuthenticated(req): Type guard to check if request is authenticated.getAuthContext(req): Get{ user, session }from request (throws if not authenticated).
Client-Only (hylekit/client)
import hyle from "hylekit/client";
// Next.js
hyle.nextjs.useSession();
hyle.nextjs.signIn.social({ provider: "google" });
// SvelteKit
hyle.sveltekit.signIn.social({ provider: "google" });hyle.sveltekit
login: Alias forsignIn.- All
better-auth/svelteclient methods.
hyle.nextjs
login: Alias forsignIn.- All
better-auth/reactclient methods.
hyle.bff
hyle.bff.createNextJsBff(config)
Creates a BFF client for Next.js that automatically attaches session headers.
hyle.bff.createSvelteKitBff(config)
Creates a BFF client for SvelteKit that automatically attaches session headers.
Types
import type {
SessionResult,
SessionData,
UserInfo,
Session,
User,
BffClientConfig,
RequestOptions,
AuthenticatedRequest,
MiddlewareOptions,
} from "hylekit";License
ISC
