Authentication
Kyrin provides a unified authentication system that combines JWT, Session, RBAC, and OAuth2 into a single Auth class. You can use the high-level Auth facade for convenience, or import individual lower-level functions for finer control.
Installation
Kyrin's auth module is built in — no extra dependencies required.
import { Auth, createAuth } from "kyrin";You can also import individual sub-modules directly:
import { createAccessToken, verifyToken } from "kyrin";
import { createSession, getSession } from "kyrin";
import { defineRole, hasPermission } from "kyrin";Quick Start
import { createAuth } from "kyrin";
const auth = createAuth({
jwtSecret: "your-secret-key-min-32-chars-long",
sessionTtl: 3600, // seconds (default: 3600)
sessionRefreshThreshold: 300, // seconds (default: 300)
});
// Sign a JWT token pair
const tokens = await auth.signToken("user-123", {
role: "admin",
});
// Verify a token
const payload = await auth.verifyToken(tokens.accessToken);
console.log(payload?.sub); // "user-123"
// Create a session
const session = auth.createSession("user-123", { role: "admin" });
// Check permissions via RBAC
auth.roles.define("admin", ["*"]);
auth.roles.assign("user-123", ["admin"]);
const canDelete = auth.roles.hasPermission("user-123", "delete:posts");Auth API Reference
createAuth(options)
Creates a new Auth instance.
interface AuthOptions {
jwtSecret: string; // Required. Secret key for signing JWT tokens.
sessionTtl?: number; // Session time-to-live in seconds (default: 3600).
sessionRefreshThreshold?: number; // Extend session if accessed within this window (default: 300).
}
const auth = createAuth({
jwtSecret: process.env.JWT_SECRET!,
sessionTtl: 7200,
sessionRefreshThreshold: 600,
});auth.signToken(userId, data?)
Creates an access + refresh token pair for a user.
const tokens = await auth.signToken("user-42", {
role: "moderator",
permissions: ["read:all", "write:posts"],
});
// tokens: { accessToken: string, refreshToken: string, expiresIn: number }| Parameter | Type | Description |
|---|---|---|
userId | string | Unique identifier for the user |
data | Partial<TokenPayload> | Optional. Extra claims (role, permissions, etc.) |
Returns: Promise<TokenPair>
auth.verifyToken(token)
Verifies both access and refresh tokens.
const payload = await auth.verifyToken(tokens.accessToken);
if (payload) {
console.log(payload.sub); // "user-42"
console.log(payload.role); // "moderator"
console.log(payload.permissions); // ["read:all", "write:posts"]
}Returns: Promise<TokenPayload | null> — null if the token is invalid or expired.
auth.verifyAccessToken(token)
Verifies only access tokens. Returns null if the token is a refresh token.
const payload = await auth.verifyAccessToken(token);auth.verifyRefreshToken(token)
Verifies only refresh tokens. Returns null if the token is an access token.
const payload = await auth.verifyRefreshToken(token);Standalone JWT Functions
For more control, you can use the low-level JWT functions directly.
Configuration
import { setJWTSecret, getJWTSecret } from "kyrin";
setJWTSecret("my-secret-key");
const secret = getJWTSecret(); // Uint8Array | nullCreating Tokens
import { createAccessToken, createRefreshToken, createTokenPair } from "kyrin";
const config = {
secret: "my-secret-key",
accessExpiry: "15m", // default: "15m"
refreshExpiry: "7d", // default: "7d"
issuer: "kyrin-app",
audience: "kyrin-users",
};
// Single token
const accessToken = await createAccessToken(
{ sub: "user-42", role: "admin" },
config
);
// Token pair
const pair = await createTokenPair(
{ sub: "user-42", role: "admin" },
config
);
// pair: { accessToken: string, refreshToken: string, expiresIn: number }Verifying Tokens
import { verifyToken, verifyAccessToken, verifyRefreshToken, decodeToken } from "kyrin";
const payload = await verifyToken(token, config);
const accessPayload = await verifyAccessToken(token, config);
const refreshPayload = await verifyRefreshToken(token, config);
// decodeToken does NOT verify the signature — only decodes the header + payload
const decoded = decodeToken(token);TokenPayload
interface TokenPayload {
sub: string; // User ID
role?: string; // User role
permissions?: string[]; // User permissions
type?: "access" | "refresh";
exp?: number; // Expiration timestamp
iat?: number; // Issued at timestamp
}JWTConfig
interface JWTConfig {
secret: string; // Required. HMAC secret key.
accessExpiry?: string; // e.g. "15m", "1h", "7d" (default: "15m")
refreshExpiry?: string; // e.g. "7d", "30d" (default: "7d")
issuer?: string; // "iss" claim
audience?: string; // "aud" claim
}Complete Example
import { createAuth } from "kyrin";
const auth = createAuth({
jwtSecret: process.env.JWT_SECRET!,
});
// --- Define roles ---
auth.roles.define("admin", ["*"]);
auth.roles.define("user", ["read:own", "update:own"]);
// --- Login endpoint ---
async function login(userId: string, password: string) {
// Validate credentials (your logic here)
const user = await findUser(userId);
if (!user || user.password !== password) {
throw new Error("Invalid credentials");
}
// Sign tokens
const tokens = await auth.signToken(userId, { role: user.role });
// Create a session
const session = auth.createSession(userId, { role: user.role });
return { tokens, sessionId: session.id };
}
// --- Protected route middleware ---
async function authMiddleware(c: Context, next: () => Promise<void>) {
const header = c.req.headers.get("Authorization");
if (!header?.startsWith("Bearer ")) {
return c.json({ error: "Unauthorized" }, 401);
}
const token = header.slice(7);
const payload = await auth.verifyAccessToken(token);
if (!payload) {
return c.json({ error: "Invalid or expired token" }, 401);
}
c.store.userId = payload.sub;
c.store.role = payload.role;
await next();
}
// --- Use in a route ---
app.get("/admin/users", authMiddleware, async (c) => {
if (!auth.roles.hasRole(c.store.userId, "admin")) {
return c.json({ error: "Forbidden" }, 403);
}
const users = await getUsers();
return c.json(users);
});Next Steps
- Session Management — Learn how to manage user sessions
- Role-Based Access Control — Define roles and permissions
- OAuth2 — Integrate Google, GitHub, Facebook, and Discord login