Bun
Authenticate users in your TypeScript applications with Aura Auth and Bun's native server
This guide walks you through creating a complete authentication flow using Aura Auth directly with the Bun native serve API.
Overview
Aura Auth and Bun both follow the web-standard Request and Response interfaces for high-performance HTTP handling. That means Aura Auth works out of the box with Bun.serve, with no external adapters or frameworks required.
Before continuing, complete the installation and initial setup:
- Quick Start Guide to create your Aura Auth instance
- TypeScript Configuration for TypeScript-specific setup
- Bun Integration App for a fully working example
Then use this guide to integrate Aura Auth with a Bun server using best practices.
What You'll Build
You will create a small Bun app with:
- a shared
src/lib/auth.tsserver configuration - a
src/index.tsentry point that mounts the auth handlers - a simple protected route example that validates the session before responding
Project Structure
Environment Setup
Create a .env.local file at the root of your project to store secrets securely.
# 32-bytes (256-bit) secret used to sign/encrypt sessions. Use a secure random value.
AURA_AUTH_SECRET="base64-or-hex-32-bytes"
AURA_AUTH_SALT="base64-or-hex-32-bytes".env.local file to version control. Use a secret manager in production.Setup Aura Auth
Create auth.ts in src/lib/ to configure Aura Auth and export the handlers. This is your single source of truth for all authentication logic.
import { createAuth } from "@aura-stack/auth"
export const auth = createAuth({
oauth: ["github"],
basePath: "/api/auth",
})
export const { handlers, jose, api } = authbasePath must match the route you mount in Bun.serve. baseURL is optional for local development but should be set to your deployed domain in production.
Mount HTTP Handlers
Define auth routes directly in Bun.serve. Any request matching /api/auth/* is handled by handlers.ALL. Bun passes standard Web Request objects, so the route can delegate directly.
import { handlers } from "@/lib/auth"
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url)
if (url.pathname.startsWith("/api/auth/")) {
return handlers.ALL(request)
}
return new Response("Not Found", { status: 404 })
},
})
console.log("Bun server running on http://localhost:3000")Usage
Get Session
Bun does not include framework-style middleware, but you can protect routes with a simple handler that validates the session before responding.
import { api, handlers } from "@/lib/auth"
Bun.serve({
port: 3000,
async fetch(request) {
const url = new URL(request.url)
if (url.pathname.startsWith("/api/auth/")) {
return handlers.ALL(request)
}
if (url.pathname === "/api/protected") {
const session = await api.getSession({
headers: request.headers,
})
if (!session.authenticated) {
return Response.json({ error: "Unauthorized", message: "Active session required." }, { status: 401 })
}
return Response.json({
message: "You have access to this protected resource.",
user: session.session.user,
})
}
return new Response("Not Found", { status: 404 })
},
})
console.log("Bun server running on http://localhost:3000")This pattern works well for small APIs or microservices. For larger applications, consider extracting route handlers into separate files.
Common Pitfalls
- Keep
basePathaligned with your route segment. If your handler route is/api/auth/*,basePathshould be/api/auth. - Always pass request headers to
api.getSession(). The session lookup needs headers so Aura Auth can read cookies. - Validate sessions before rendering private responses. Check
session.authenticatedbefore exposing sensitive data. - Use TypeScript for safer session access. Type-guard your session object to avoid runtime errors when accessing user fields.