From f41873c1df0bcec23457fdf88bb8ed94e8e87132 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Wed, 1 Apr 2026 19:29:13 -0500 Subject: [PATCH 1/3] docs: add integration docs for supported frameworks --- apps/bun/src/index.ts | 6 +- apps/bun/src/{ => lib}/auth.ts | 0 apps/bun/tsconfig.json | 11 +- apps/elysia/src/plugins/with-auth.ts | 2 +- apps/hono/tsconfig.json | 12 +- apps/vercel/api/auth/index.ts | 1 + docs/src/content/docs/integrations/astro.mdx | 93 +++++++ docs/src/content/docs/integrations/bun.mdx | 119 ++++++++ .../docs/integrations/cloudflare-workers.mdx | 91 +++++++ docs/src/content/docs/integrations/deno.mdx | 137 ++++++++++ docs/src/content/docs/integrations/elysia.mdx | 147 ++++++++++ .../src/content/docs/integrations/express.mdx | 256 ++++++++++++++++++ docs/src/content/docs/integrations/hono.mdx | 148 ++++++++++ docs/src/content/docs/integrations/meta.json | 22 ++ docs/src/content/docs/integrations/nuxt.mdx | 137 ++++++++++ docs/src/content/docs/integrations/oak.mdx | 212 +++++++++++++++ .../docs/integrations/react-router.mdx | 99 +++++++ .../integrations/supabase-edge-functions.mdx | 126 +++++++++ .../docs/integrations/tanstack-start.mdx | 125 +++++++++ .../integrations/vercel-edge-functions.mdx | 114 ++++++++ docs/src/content/docs/meta.json | 1 + 21 files changed, 1846 insertions(+), 13 deletions(-) rename apps/bun/src/{ => lib}/auth.ts (100%) create mode 100644 docs/src/content/docs/integrations/astro.mdx create mode 100644 docs/src/content/docs/integrations/bun.mdx create mode 100644 docs/src/content/docs/integrations/cloudflare-workers.mdx create mode 100644 docs/src/content/docs/integrations/deno.mdx create mode 100644 docs/src/content/docs/integrations/elysia.mdx create mode 100644 docs/src/content/docs/integrations/express.mdx create mode 100644 docs/src/content/docs/integrations/hono.mdx create mode 100644 docs/src/content/docs/integrations/meta.json create mode 100644 docs/src/content/docs/integrations/nuxt.mdx create mode 100644 docs/src/content/docs/integrations/oak.mdx create mode 100644 docs/src/content/docs/integrations/react-router.mdx create mode 100644 docs/src/content/docs/integrations/supabase-edge-functions.mdx create mode 100644 docs/src/content/docs/integrations/tanstack-start.mdx create mode 100644 docs/src/content/docs/integrations/vercel-edge-functions.mdx diff --git a/apps/bun/src/index.ts b/apps/bun/src/index.ts index 1315c35a..2922d13c 100644 --- a/apps/bun/src/index.ts +++ b/apps/bun/src/index.ts @@ -1,4 +1,4 @@ -import { handlers, api } from "./auth" +import { handlers, api } from "@/lib/auth" Bun.serve({ port: 3000, @@ -11,7 +11,7 @@ Bun.serve({ }, "/api/protected": async (request) => { const session = await api.getSession({ - headers: request.headers, + headers: request.headers, }) if (!session.authenticated) { return Response.json( @@ -27,6 +27,6 @@ Bun.serve({ message: "You have access to this protected resource.", session, }) - }, + }, }, }) diff --git a/apps/bun/src/auth.ts b/apps/bun/src/lib/auth.ts similarity index 100% rename from apps/bun/src/auth.ts rename to apps/bun/src/lib/auth.ts diff --git a/apps/bun/tsconfig.json b/apps/bun/tsconfig.json index cc223272..34c825d8 100644 --- a/apps/bun/tsconfig.json +++ b/apps/bun/tsconfig.json @@ -1,5 +1,10 @@ { - "extends": "@aura-stack/tsconfig/bun.json", - "include": ["src"], - "exclude": ["dist", "node_modules"] + "extends": "@aura-stack/tsconfig/bun.json", + "compilerOptions": { + "paths": { + "@/*": ["./src/*"], + }, + }, + "include": ["src"], + "exclude": ["dist", "node_modules"], } diff --git a/apps/elysia/src/plugins/with-auth.ts b/apps/elysia/src/plugins/with-auth.ts index 92e44a4d..64184e63 100644 --- a/apps/elysia/src/plugins/with-auth.ts +++ b/apps/elysia/src/plugins/with-auth.ts @@ -7,7 +7,7 @@ export const withAuthPlugin = new Elysia({ name: "with-auth" }) const session = await api.getSession({ headers: ctx.request.headers, }) - if (!session!.authenticated) { + if (!session.authenticated) { return { session: null } } return { session } diff --git a/apps/hono/tsconfig.json b/apps/hono/tsconfig.json index 11145bc8..8902be17 100644 --- a/apps/hono/tsconfig.json +++ b/apps/hono/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "@aura-stack/tsconfig/bun.json", - "compilerOptions": { - "jsxImportSource": "hono/jsx" - }, - "include": ["src"], - "exclude": ["dist", "node_modules"] + "extends": "@aura-stack/tsconfig/bun.json", + "compilerOptions": { + "jsxImportSource": "hono/jsx", + }, + "include": ["src"], + "exclude": ["dist", "node_modules"], } diff --git a/apps/vercel/api/auth/index.ts b/apps/vercel/api/auth/index.ts index 032f1aa2..3e6cef04 100644 --- a/apps/vercel/api/auth/index.ts +++ b/apps/vercel/api/auth/index.ts @@ -1,3 +1,4 @@ + import { handlers } from "../_auth.js" export const GET = async (request: Request) => { diff --git a/docs/src/content/docs/integrations/astro.mdx b/docs/src/content/docs/integrations/astro.mdx new file mode 100644 index 00000000..ece816a4 --- /dev/null +++ b/docs/src/content/docs/integrations/astro.mdx @@ -0,0 +1,93 @@ +--- +title: Astro +description: Build your first authentication flow with Aura Auth and Astro +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in an **Astro** application. + +## Overview + +Astro's API endpoints (`pages/api/...`) natively receive and return Web Standard `Request` and `Response` objects, making it a perfect fit for Aura Auth's unified handlers. + + + + + +### Install Aura Auth + +Install the package: + +```npm +npm install @aura-stack/auth +``` + + + + + +### Create an Auth Configuration + +Set up your core configuration file anywhere securely accessible to your server endpoints. + +```ts title="src/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + secret: import.meta.env.AURA_AUTH_SECRET, +}) +``` + + + + + +### Integrate with Astro's API routes + +Create a catch-all route under your API directory `src/pages/api/auth/[...auth].ts`. We export the `ALL` handler to automatically take care of GET, POST, and other HTTP methods. + +```ts title="src/pages/api/auth/[...auth].ts" lineNumbers +import { auth } from "../../../auth" +import type { APIRoute } from "astro" + +export const ALL: APIRoute = ({ request }) => { + return auth.handlers.ALL(request) +} +``` + + + Ensure your `basePath` option in `createAuth` matches the actual route (`/api/auth`) if you place it outside the standard root + `/auth` path. + + + + + + +### Access the Session in Astro Components + +You can retrieve the session during Server-Side Rendering (SSR) directly in your Astro component's frontmatter! + +```astro title="src/pages/dashboard.astro" lineNumbers +--- +import { auth } from "../auth"; + +// Pass Astro.request to interact natively with headers +const session = await auth.api.getSession(Astro.request); + +if (!session) { + return Astro.redirect("/login"); +} +--- + + + +

Welcome, {session.user.name}!

+ Avatar + + +``` + +
+ +
diff --git a/docs/src/content/docs/integrations/bun.mdx b/docs/src/content/docs/integrations/bun.mdx new file mode 100644 index 00000000..9c8f07b2 --- /dev/null +++ b/docs/src/content/docs/integrations/bun.mdx @@ -0,0 +1,119 @@ +--- +title: Bun +description: 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. This 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](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with a Bun server using best practices. + + + + + +### Project Structure + +```files +bun-app +├── src +│ ├── lib +│ │ └── auth.ts +│ └── index.ts +├── tsconfig.json +└── package.json +``` + + + + + +### Create an Auth Instance + +Create `auth.ts` in `src/lib/` and configure the OAuth providers and options for your Aura Auth instance. + +```ts title="lib/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { handlers } = auth +``` + +`basePath` must match the route you expose in Bun.serve. + + + + + +### Integrate with Bun.serve + +Define auth routes directly in `Bun.serve`. Any request matching `/api/auth/*` is handled by `handlers.ALL`. + +```ts title="index.ts" lineNumbers +import { handlers } from "@/lib/auth" + +Bun.serve({ + port: 3000, + routes: { + "/api/auth/*": handlers.ALL, + }, +}) + +console.log("Bun server running on http://localhost:3000") +``` + + + + + +### Protecting Routes + +Bun does not include framework-style middleware, but you can protect routes with a small helper-style handler that validates the current session. + +```ts title="index.ts" lineNumbers +import { auth, handlers } from "@/lib/auth" + +Bun.serve({ + port: 3000, + routes: { + "/api/auth/*": handlers.ALL, + "/api/protected": async (request) => { + const session = await auth.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.", + session, + }) + }, + }, +}) + +console.log("Bun server running on http://localhost:3000") +``` + + + + diff --git a/docs/src/content/docs/integrations/cloudflare-workers.mdx b/docs/src/content/docs/integrations/cloudflare-workers.mdx new file mode 100644 index 00000000..3e615b3b --- /dev/null +++ b/docs/src/content/docs/integrations/cloudflare-workers.mdx @@ -0,0 +1,91 @@ +--- +title: Cloudflare Workers +description: Build your first authentication flow with Aura Auth and Cloudflare Workers +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** with **Cloudflare Workers**. + +## Overview + +Cloudflare Workers use the Fetch API (`Request` and `Response`), which matches Aura Auth's framework-agnostic design. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with a Cloudflare Worker using best practices. + + + + + +### Project Structure + +```files +cloudflare-app +├── src +│ ├── lib +│ │ └── auth.ts +│ └── index.ts +├── tsconfig.json +├── package.json +└── wrangler.jsonc +``` + + + + + +### Secret Variables Setup + +Using the `wrangler` CLI or the Cloudflare dashboard, add the required secret environment variables. Workers read secrets from the `env` argument rather than `process.env`. + +```bash +npx wrangler secret put AURA_AUTH_SECRET +npx wrangler secret put AURA_AUTH_SALT +npx wrangler secret put AURA_AUTH_GITHUB_CLIENT_ID +npx wrangler secret put AURA_AUTH_GITHUB_CLIENT_SECRET +``` + +As a second option, you can define the variables locally in a `.env` file and generate the `Env` type with the `wrangler` CLI: + +```bash +wrangler types +``` + + + + + +### Initialize Aura Auth per Request + +Because Workers pass environment variables into the `fetch` execution context, keep your auth setup in a separate module and route `/api/auth/*` requests to `handlers.ALL`. + +```ts title="src/index.ts" lineNumbers +import { handlers } from "@/lib/auth" + +export default { + async fetch(request: Request): Promise { + const pathname = new URL(request.url).pathname + if (pathname.startsWith("/api/auth/")) { + return await handlers.ALL(request) + } + return new Response("Not Found", { status: 404 }) + }, +} satisfies ExportedHandler +``` + + + + + +### Securing the Worker edge cases + +Because edge workers execute globally across multiple locations, standard Node.js APIs are not always available. + +Aura Auth is runtime-agnostic and uses the Web Crypto API and web standards, so it works without `node:crypto` imports in your Worker deployment. + + + + diff --git a/docs/src/content/docs/integrations/deno.mdx b/docs/src/content/docs/integrations/deno.mdx new file mode 100644 index 00000000..e83a008d --- /dev/null +++ b/docs/src/content/docs/integrations/deno.mdx @@ -0,0 +1,137 @@ +--- +title: Deno +description: Authenticate users in your TypeScript applications with Aura Auth and Deno's native server +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** directly with **Deno**. + +## Overview + +Aura Auth and Deno both follow the web-standard `Request` and `Response` interfaces for high-performance HTTP handling. This means Aura Auth works out of the box with `Deno.serve`, with no external adapters or frameworks required. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with a Deno server using best practices. + + + + + +### Project Structure + +```files +deno-app +├── src +│ ├── lib +│ │ └── auth.ts +│ └── index.ts +└── deno.json +``` + + + + + +### Create an Auth Instance + +Create `auth.ts` in `src/lib/` and configure the OAuth providers and options for your Aura Auth instance. + +```ts title="lib/auth.ts" +import { createAuth } from "npm:@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { handlers } = auth +``` + +`basePath` must match the route you expose in Deno.serve. + + + + + +### Integrate with Deno.serve + +Define auth routes directly in `Deno.serve`. Any request matching `/api/auth/*` is handled by `handlers.ALL`. + +```ts title="index.ts" lineNumbers +import { handlers } from "./lib/auth.ts" + +Deno.serve({ port: 3000 }, async (request) => { + const pathname = new URL(request.url).pathname + + if (pathname.startsWith("/api/auth/")) { + return await handlers.ALL(request) + } + + return new Response("Not Found", { status: 404 }) +}) +``` + + + + + +### Protecting Routes + +Deno does not include framework-style middleware, but you can protect routes with a small helper-style handler that validates the current session. + +```ts title="index.ts" lineNumbers +import { auth, handlers } from "./lib/auth.ts" + +Deno.serve({ port: 3000 }, async (request) => { + const pathname = new URL(request.url).pathname + + switch (pathname) { + case "/api/protected": { + const session = await auth.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.", + session, + }) + } + + default: { + if (pathname.startsWith("/api/auth/")) { + return await handlers.ALL(request) + } + + return new Response("Not Found", { status: 404 }) + } + } +}) +``` + + + + + +### Run the App + +Deno enforces security by default. Make sure you allow reading from the environment and receiving network connections. + +```bash +deno run --allow-net --allow-env src/index.ts +``` + + + + diff --git a/docs/src/content/docs/integrations/elysia.mdx b/docs/src/content/docs/integrations/elysia.mdx new file mode 100644 index 00000000..409f220a --- /dev/null +++ b/docs/src/content/docs/integrations/elysia.mdx @@ -0,0 +1,147 @@ +--- +title: Elysia +description: Build your first authentication flow with Aura Auth and Elysia +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in an **Elysia** server environment. + +## Overview + +Aura Auth and Elysia, an ergonomic web framework for Bun, both follow the web-standard `Request` and `Response` interfaces for high-performance HTTP handling. This means Aura Auth works out of the box with Elysia, with no external adapters or frameworks required. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with an Elysia server using best practices. + + + + + +### Project Structure + +```files +elysia-app +├── src +│ ├── lib +│ │ └── auth.ts +│ ├── plugins +│ │ └── with-auth.ts +│ └── index.ts +├── tsconfig.json +└── package.json +``` + + + + + +### Create an Auth Instance + +Create `auth.ts` in `src/lib/` and configure the OAuth providers and options for your Aura Auth instance. + +```ts title="lib/auth.ts" lineNumbers +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { handlers } = auth +``` + +`basePath` must match the route you expose in Elysia. + + + + + +### Integrate with Elysia + +Mount auth handlers to process all traffic directed to the `/api/auth/*` path in your Elysia app: + +```ts title="index.ts" lineNumbers +import { Elysia } from "elysia" +import { auth } from "@/lib/auth" + +const app = new Elysia() + +app.all("/api/auth/*", (ctx) => { + return auth.handlers.ALL(ctx.request) +}) + +app.listen(3000) +``` + + + + + +### Add Elysia Plugin for Session Management + +```ts title="plugins/with-auth.ts" lineNumbers +import { Elysia } from "elysia" +import { auth } from "@/lib/auth" + +export const withAuthPlugin = new Elysia({ name: "with-auth" }) + .resolve({ as: "scoped" }, async (ctx) => { + try { + const session = await auth.api.getSession({ + headers: ctx.request.headers, + }) + if (!session.authenticated) { + return { session: null } + } + return { session } + } catch { + return { session: null } + } + }) + .get("/api/auth/me", ({ session }) => session) +``` + + + + + +### Protecting Routes + +Use the plugin in your app and protect routes by checking for an active session: + +```ts title="index.ts" lineNumbers +import { Elysia } from "elysia" +import { auth } from "@/lib/auth" +import { withAuthPlugin } from "@/plugins/with-auth" + +const app = new Elysia() + +app.all("/api/auth/*", (ctx) => { + return auth.handlers.ALL(ctx.request) +}) + +app.use(withAuthPlugin).get("/api/protected", (ctx) => { + if (!ctx.session?.authenticated) { + return ctx.json( + { + error: "Unauthorized", + message: "Active session required.", + }, + { status: 401 } + ) + } + + return ctx.json({ + message: "You have access to this protected resource.", + session: ctx.session, + }) +}) + +app.listen(3000) +``` + + + + diff --git a/docs/src/content/docs/integrations/express.mdx b/docs/src/content/docs/integrations/express.mdx new file mode 100644 index 00000000..6196b31c --- /dev/null +++ b/docs/src/content/docs/integrations/express.mdx @@ -0,0 +1,256 @@ +--- +title: Express +description: Build your first authentication flow with Aura Auth and Express +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in an **Express** application. + +## Overview + +Express is built around Node.js `IncomingMessage` and `ServerResponse` streams rather than modern web-standard `Request` and `Response` objects. It requires a small adapter to bridge Express and Aura Auth's web-standard handlers. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with an Express server using best practices. + + + + + +### Project Structure + +```files +express-app +├── src +│ ├── lib +│ │ ├── auth.ts +│ │ └── handler.ts +│ ├── middlewares +│ │ └── verify-session.ts +│ ├── types.d.ts +│ └── index.ts +├── tsconfig.json +└── package.json +``` + + + + + +### Create an Auth Instance + +Create an `auth.ts` file in your project to configure authentication. + +```ts title="lib/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { handlers } = auth +``` + +`basePath` must match the route you expose in your Express app. + + + + + +### Handler Adapter + +Because Express uses `IncomingMessage` and `ServerResponse`, create an adapter that converts them into the web-standard `Request` and `Response` objects Aura Auth expects. + +```ts title="lib/handler.ts" lineNumbers +import { handlers } from "@/lib/auth.js" +import type { Request, Response } from "express" + +const splitSetCookieHeaderValue = (value: string): string[] => { + return value + .split(/,(?=\s*[^;,\s]+=)/g) + .map((cookie) => cookie.trim()) + .filter(Boolean) +} + +/** + * Convert an Express Request to a Web API Request so it can be handled + * by the framework-agnostic Aura Auth handlers. + */ +export const toWebRequest = (req: Request): globalThis.Request => { + const method = req.method ?? "GET" + const protocol = req.protocol ?? "http" + const host = req.get("host") ?? "localhost" + + const baseURL = `${protocol}://${host}` + const url = new URL(req.originalUrl ?? req.url, baseURL) + + const headers = new Headers() + for (const [key, value] of Object.entries(req.headers)) { + if (Array.isArray(value)) { + for (const v of value) headers.append(key, v) + } else if (value !== undefined) { + headers.set(key, value) + } + } + + const body = method !== "GET" && method !== "HEAD" && req.body !== undefined ? JSON.stringify(req.body) : undefined + if (body !== undefined) { + headers.set("content-type", "application/json") + } + + return new globalThis.Request(url, { + method, + headers, + body, + }) +} + +/** + * Forward the Web API Response back to the Express Response. + * Handles redirects, multiple Set-Cookie headers, and JSON/text bodies. + */ +export const toExpressResponse = async (webResponse: globalThis.Response, res: Response) => { + for (const [key, value] of webResponse.headers.entries()) { + if (key.toLowerCase() === "set-cookie") { + const cookies = webResponse.headers.getSetCookie?.() ?? splitSetCookieHeaderValue(value) + + for (const cookie of cookies) { + res.append("Set-Cookie", cookie) + } + } else { + res.setHeader(key, value) + } + } + + res.status(webResponse.status) + if (webResponse.status >= 300 && webResponse.status < 400) { + const location = webResponse.headers.get("location") ?? "/" + return res.redirect(webResponse.status, location) + } + const contentType = webResponse.headers.get("content-type") + if (contentType?.includes("application/json")) { + const data = await webResponse.json() + return res.json(data) + } + const text = await webResponse.text() + return res.send(text) +} + +/** + * Express middleware that bridges Aura Auth Web-API handlers to Express. + * Mount this on the `basePath` configured in `createAuth()` (default: `/api/auth`). + */ +export const toExpressHandler = async (req: Request, res: Response) => { + const webResponse = await handlers.ALL(toWebRequest(req)) + return toExpressResponse(webResponse, res) +} +``` + + + + + +### Integrate with Express + +Mount the Aura Auth handlers inside your Express app using the Web Standard adapter: + +```ts title="index.ts" lineNumbers +import express, { type Express } from "express" +import { toExpressHandler } from "@/lib/handler.js" +import { verifySession } from "@/middlewares/verify-session.js" + +const app: Express = express() + +app.use(express.json()) +app.use(express.urlencoded({ extended: true })) + +app.all("/api/auth/*", toExpressHandler) + +app.listen(3000, () => { + console.log("Server running on http://localhost:3000") +}) +``` + + + + + +### Middleware + +Middlewares are a common pattern in Express apps for protecting routes. You can create a middleware that checks for an active session before allowing access to protected routes. + +```ts title="middlewares/verify-session.ts" lineNumbers +import { auth } from "@/lib/auth.js" +import { toWebRequest } from "@/lib/handler.js" +import type { Request, Response, NextFunction } from "express" + +export const verifySession = async (req: Request, res: Response, next: NextFunction) => { + const webRequest = toWebRequest(req) + const session = await auth.api.getSession({ + headers: webRequest.headers, + }) + if (!session.authenticated) { + return res.status(401).json({ + error: "Unauthorized", + message: "You must be signed in to access this resource.", + }) + } + res.locals.session = session.session + return next() +} +``` + +Express doesn't infer the `Locals` type automatically, so extend it to include the session: + +```ts title="types.d.ts" lineNumbers +import { Session } from "@aura-stack/auth" + +declare global { + namespace Express { + interface Locals { + session?: Session + } + } +} +``` + + + + + +### Access the Session + +To access the active session in your protected Express routes, you can use the `auth.api.getSession` method: + +```ts title="index.ts" lineNumbers +import express, { type Express } from "express" +import { toExpressHandler } from "@/lib/handler.js" +import { verifySession } from "@/middlewares/verify-session.js" + +const app: Express = express() + +app.use(express.json()) +app.use(express.urlencoded({ extended: true })) + +app.all("/api/auth/*", toExpressHandler) + +app.get("/api/protected", verifySession, (req, res) => { + const session = res.locals.session + return res.json({ + message: "You have access to this protected resource.", + session, + }) +}) + +app.listen(3000, () => { + console.log("Server running on http://localhost:3000") +}) +``` + + + + diff --git a/docs/src/content/docs/integrations/hono.mdx b/docs/src/content/docs/integrations/hono.mdx new file mode 100644 index 00000000..675b2379 --- /dev/null +++ b/docs/src/content/docs/integrations/hono.mdx @@ -0,0 +1,148 @@ +--- +title: Hono +description: Build your first authentication flow with Aura Auth and Hono +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in a **Hono** application. + +## Overview + +Hono is built on web standards (`Request` and `Response`), which makes integrating Aura Auth incredibly simple and elegant. You can use the new `ALL` handler to cover all authentication HTTP methods in a single route. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with an Hono using best practices. + + + + + +### Project Structure + +```files +hono-app +├── src +│ ├── lib +│ │ ├── auth.ts +│ ├── middlewares +│ │ └── with-auth.ts +│ └── index.ts +├── tsconfig.json +└── package.json +``` + + + + + +### Create an Auth Instance + +Create an `auth.ts` file in your project to configure authentication. + +```ts title="lib/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], +}) + +export const { handlers, api, jose } = auth +``` + +`basePath` must match the route you expose in your Hono app. + + + + + +### Integrate with Hono + +Mount the Aura Auth handlers using a wildcard route `/*` under your `/api/auth` subpath. You can pass `c.req.raw`, which is the native Web Standard `Request` object. + +```ts title="index.ts" lineNumbers +import { Hono } from "hono" +import { handlers } from "@/lib/auth" + +const app = new Hono() + +app.all("/api/auth/*", async (ctx) => { + return await handlers.ALL(ctx.req.raw) +}) + +export default app +``` + + + + + +### Middleware + +Middleware is a powerful way to protect your routes and access session data across your app. Create a `with-auth.ts` file in `src/middlewares`: + +```ts title="middlewares/with-auth.ts" lineNumbers +import { api } from "@/lib/auth" +import { createMiddleware } from "hono/factory" +import type { Session } from "@aura-stack/auth" + +/** + * Type definition for Hono's Context Variables to include the session. + */ +export type AuthVariables = { + session: Session +} + +export const withAuth = createMiddleware<{ Variables: AuthVariables }>(async (ctx, next) => { + try { + const session = await api.getSession({ + headers: ctx.req.raw.headers, + }) + if (!session.authenticated) { + return ctx.json({ error: "Unauthorized", message: "Active session required." }, 401) + } + ctx.set("session", session.session) + return await next() + } catch { + return ctx.json({ error: "Unauthorized", message: "Active session required." }, 401) + } +}) +``` + + + + + +### Protecting Routes + +```ts title="index.ts" lineNumbers +import { Hono } from "hono" +import { handlers } from "@/lib/auth" +import { type AuthVariables, withAuth } from "@/middleware/with-auth" + +const app = new Hono<{ Variables: AuthVariables }>() + +app.get("/", (ctx) => { + return ctx.text("Welcome to the Aura Auth Hono App!") +}) + +app.all("/api/auth/*", async (ctx) => { + return await handlers.ALL(ctx.req.raw) +}) + +app.get("/api/protected", withAuth, (ctx) => { + const session = ctx.get("session") + return ctx.json({ + message: "You have access to this protected resource.", + session, + }) +}) + +export default app +``` + + + + diff --git a/docs/src/content/docs/integrations/meta.json b/docs/src/content/docs/integrations/meta.json new file mode 100644 index 00000000..f5f2e778 --- /dev/null +++ b/docs/src/content/docs/integrations/meta.json @@ -0,0 +1,22 @@ +{ + "title": "Integrations", + "pages": [ + "---Frontend---", + "astro", + "next", + "nuxt", + "react-router", + "tanstack-start", + "---Backend---", + "bun", + "deno", + "elysia", + "express", + "hono", + "oak", + "---Edge---", + "cloudflare-workers", + "supabase-edge-functions", + "vercel-edge-functions" + ] +} diff --git a/docs/src/content/docs/integrations/nuxt.mdx b/docs/src/content/docs/integrations/nuxt.mdx new file mode 100644 index 00000000..9f3f120d --- /dev/null +++ b/docs/src/content/docs/integrations/nuxt.mdx @@ -0,0 +1,137 @@ +--- +title: Nuxt.js +description: Build your first authentication flow with Aura Auth and Nuxt (Nitro) +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in a **Nuxt.js** application. + +## Overview + +Nuxt runs on the Nitro server engine, which natively uses the `h3` event handler. Aura Auth is highly compatible because you can map standard Web Requests via Nitro's `toWebRequest` utility or directly mount Aura handles. + + + + + +### Install Aura Auth + +Install the package in your Nuxt project: + +```npm +npm install @aura-stack/auth +``` + + + + + +### Create an Auth Configuration + +Create an `auth.ts` inside your `server/utils` or `server` directory so it is automatically imported or easily accessed by Nitro endpoints. + +```ts title="server/utils/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + secret: process.env.AURA_AUTH_SECRET!, +}) +``` + + + + + +### Integrate with Nitro (server/routes) + +Create a wildcard catch-all route that delegates to Aura's `ALL` handler. Nitro provides `toWebRequest` to ensure `auth.handlers.ALL` receives a standard `Request` object. + +```ts title="server/routes/auth/[...path].ts" lineNumbers +export default defineEventHandler((event) => { + // Convert the H3 event to a Web Request + const request = toWebRequest(event) + + // Pass it to Aura Auth + return auth.handlers.ALL(request) +}) +``` + +Aura Auth endpoints will now be served at `/auth/...` + + + + + +### Accessing the Session in Nuxt + +You can protect your API endpoints by reading the session from the incoming event. + +```ts title="server/api/protected.ts" lineNumbers +export default defineEventHandler(async (event) => { + const request = toWebRequest(event) + const session = await auth.api.getSession(request) + + if (!session) { + throw createError({ + statusCode: 401, + statusMessage: "Unauthorized", + }) + } + + return { + message: "You are viewing secure data", + user: session.user, + } +}) +``` + + + + + +### Setting up the Client UI + +With Nuxt, you can use the built-in `createAuthClient` utility to handle authentication directly from your Vue components. + +```vue title="app.vue" lineNumbers + + + +``` + + + + diff --git a/docs/src/content/docs/integrations/oak.mdx b/docs/src/content/docs/integrations/oak.mdx new file mode 100644 index 00000000..bf9dd29d --- /dev/null +++ b/docs/src/content/docs/integrations/oak.mdx @@ -0,0 +1,212 @@ +--- +title: Oak +description: Build your first authentication flow with Aura Auth and Oak (Deno) +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** inside an **Oak** application running on Deno. + +## Overview + +Oak is a popular middleware framework for Deno. Because Oak builds on Deno's native web APIs, you can adapt requests from `ctx.request.source` to a standard `Request` object with minimal glue code. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with Oak using best practices. + + + + + +### Project Structure + +```files +oak-app +├── src +│ ├── lib +│ │ ├── auth.ts +│ │ ├── handler.ts +│ ├── middlewares +│ │ └── with-auth.ts +│ └── index.ts +├── tsconfig.json +└── package.json +``` + + + + + +### Create an Auth Instance + +Set up your `auth.ts` file and configure Aura Auth for your Oak app. + +```ts title="auth.ts" +import { createAuth } from "npm:@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], +}) + +export const { handlers, api } = auth +``` + +`basePath` must match the route you expose in your Oak app. + + + + + +### Handler Adapter + +Oak does not call Aura Auth handlers directly, so create a small adapter that forwards Oak requests to the web-standard handlers Aura Auth expects. + +```ts title="lib/handler.ts" lineNumbers +import { handlers } from "@/lib/auth.ts" +import type { RouterContext } from "@oak/oak" + +export const toSetHeaders = (ctx: RouterContext, headers: Headers) => { + for (const [key, value] of headers.entries()) { + ctx.response.headers.set(key, value) + } +} + +const isRedirect = (response: Response) => { + const location = response.headers.get("Location") + return location !== null && response.status >= 300 && response.status < 400 +} + +export const toOakHandler = async (ctx: RouterContext<"/api/auth/(.*)">) => { + const handler = handlers[ctx.request.method as keyof typeof handlers] + if (!handler) { + ctx.response.status = 405 + ctx.response.body = { error: "Method Not Allowed" } + return + } + const toWebRequest = ctx.request.source + if (!toWebRequest) { + ctx.response.status = 400 + ctx.response.body = { error: "Bad Request" } + return + } + const response = await handler(toWebRequest) + if (isRedirect(response)) { + const location = response.headers.get("Location")! + ctx.response.status = 302 + toSetHeaders(ctx, response.headers) + ctx.response.redirect(location) + return + } + const body = await response.json() + toSetHeaders(ctx, response.headers) + ctx.response.body = body +} +``` + + + + + +### Integrate with Oak + +Set up a catch-all route in Oak that forwards authentication requests to the adapter. The adapter takes care of converting Oak's request context into the web-standard request Aura Auth needs. + +```ts title="index.ts" lineNumbers +import { Application, Router } from "@oak/oak" +import { toOakHandler } from "@/lib/handler.ts" +import type { GlobalState } from "@/middlewares/with-auth.ts" + +const router = new Router() +const app = new Application() + +router.all("/api/auth/(.*)", toOakHandler) + +app.use(router.routes()) +await app.listen({ port: 3000 }) +``` + + + + + +### Middleware + +Create a middleware that loads the active session into Oak state so protected routes can reuse it. + +```ts title="middlewares/with-auth.ts" lineNumbers +import { api } from "@/lib/auth.ts" +import type { Session } from "@aura-stack/auth" +import type { Next, RouteParams, RouterContext } from "@oak/oak" + +const unauthorizedBody = { + error: "Unauthorized", + message: "Active session required.", +} + +export interface GlobalState { + session: Session | null +} + +export type RouterContextWithState = RouteParams> = RouterContext< + Route, + Params, + GlobalState +> + +export const withAuth = async (ctx: RouterContextWithState, next: Next) => { + try { + const session = await api.getSession({ + headers: ctx.request.headers, + }) + if (!session.authenticated) { + ctx.response.status = 401 + ctx.response.body = unauthorizedBody + return + } + ctx.state.session = session.session + return await next() + } catch { + ctx.response.status = 401 + ctx.response.body = unauthorizedBody + } +} +``` + + + + + +### Protecting Routes + +Use the middleware in your app and guard protected routes with the session it provides. + +```ts title="index.ts" lineNumbers +import { Application, Router } from "@oak/oak" +import { toOakHandler } from "@/lib/handler.ts" +import { type GlobalState, withAuth } from "@/middlewares/with-auth.ts" + +const router = new Router() +const app = new Application() + +router.get("/", (ctx) => { + ctx.response.body = "Welcome to Aura Auth Oak App!" +}) + +router.all("/api/auth/(.*)", toOakHandler) + +router.get("/api/protected", withAuth, (ctx) => { + ctx.response.body = { + message: "You have access to this protected resource.", + session: ctx.state.session, + } +}) + +app.use(router.routes()) +await app.listen({ port: 3000 }) +``` + + + + diff --git a/docs/src/content/docs/integrations/react-router.mdx b/docs/src/content/docs/integrations/react-router.mdx new file mode 100644 index 00000000..32c5674a --- /dev/null +++ b/docs/src/content/docs/integrations/react-router.mdx @@ -0,0 +1,99 @@ +--- +title: React Router (Remix) +description: Build your first authentication flow with Aura Auth and React Router v7 +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in a **React Router v7** (formerly Remix) application. + +## Overview + +React Router API loaders and actions run on the server and receive the native Web `Request` object. This makes integrating Aura Auth a breeze by exporting loaders and actions directly from the unified handlers. + + + + + +### Install Aura Auth + +Install the package in your React Router project: + +```npm +npm install @aura-stack/auth +``` + + + + + +### Create an Auth Configuration + +Create an `app/auth.server.ts` file. Notice the `.server.ts` extension ensures this code is never bundled with client-side code. + +```ts title="app/auth.server.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + // Assumes process.env or context access depending on your deployment adapter + secret: process.env.AURA_AUTH_SECRET!, +}) +``` + + + + + +### Integrate the Handlers + +React Router requires a splat route to capture all authentication endpoints (like `/auth/signIn/github`, `/auth/session`, `/auth/callback/...`). + +Create `app/routes/auth.$.tsx`. + +```ts title="app/routes/auth.$.tsx" lineNumbers +import { auth } from "../auth.server" +import type { LoaderFunctionArgs, ActionFunctionArgs } from "react-router" + +// Handle all GET requests (signIn, callback, session csrfToken) +export async function loader({ request }: LoaderFunctionArgs) { + return auth.handlers.GET(request) +} + +// Handle all POST requests (signOut, callback if configured) +export async function action({ request }: ActionFunctionArgs) { + return auth.handlers.POST(request) +} +``` + +Aura Auth will now elegantly handle any Request interacting with the `/auth/*` baseline boundary. + + + + + +### Accessing secure session data + +Within any other loader/action, use the underlying `getSession` programmatically to check authentication dynamically without a fetch cascade. + +```ts title="app/routes/dashboard.tsx" lineNumbers +import { redirect } from "react-router" +import { auth } from "../auth.server" +import type { LoaderFunctionArgs } from "react-router" + +export async function loader({ request }: LoaderFunctionArgs) { + const session = await auth.api.getSession(request); + + if (!session) { + throw redirect("/login"); + } + + return { user: session.user }; +} + +export default function Dashboard() { + return

Dashboard Loaded!

+} +``` + +
+ +
diff --git a/docs/src/content/docs/integrations/supabase-edge-functions.mdx b/docs/src/content/docs/integrations/supabase-edge-functions.mdx new file mode 100644 index 00000000..72e30d5d --- /dev/null +++ b/docs/src/content/docs/integrations/supabase-edge-functions.mdx @@ -0,0 +1,126 @@ +--- +title: Supabase Edge Functions +description: Build your first authentication flow with Aura Auth and Supabase Edge Functions +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in **Supabase Edge Functions** (built on Deno). + +## Overview + +Supabase Edge Functions run on Deno and use the web-standard Fetch API (`Request` and `Response`). Aura Auth works out of the box with this runtime model. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with a Supabase Edge Function using best practices. + + + + + +### Project Structure + +```files +supabase-app +├── functions +│ ├── _shared +│ │ └── auth.ts +│ ├── auth +│ │ ├── deno.json +│ │ └── index.ts +├── config.toml +└── package.json +``` + + + + + +### Set up `config.toml` + +This defines the edge function's route and permissions. Ensure the `index.ts` entrypoint is correctly referenced. + +```toml title="config.toml" +[functions.auth] +enabled = true +# disable JWT verification for faster local development. DO NOT disable in production. +verify_jwt = false +import_map = "./functions/auth/deno.json" +# Uncomment to specify a custom file path to the entrypoint. +# Supported file extensions are: .ts, .js, .mjs, .jsx, .tsx +entrypoint = "./functions/auth/index.ts" +``` + + + + + +### Create an Auth Instance + +Create an `auth.ts` file in your project to configure authentication. + +```ts title="supabase-app/functions/_shared/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { handlers, api } = auth +``` + +`basePath` must match the route you expose in your Supabase function. + + + + + +### Integrate with `Deno.serve` + +Using Supabase Edge Function execution, define your handler with `Deno.serve`. + +```ts title="supabase/functions/auth/index.ts" lineNumbers +import { handlers, api } from "../_shared/auth.ts" + +// Follow this setup guide to integrate the Deno language api with your editor: +// https://deno.land/manual/getting_started/setup_your_environment +// This enables autocomplete, go to definition, etc. +import "@supabase/functions-js/edge-runtime.d.ts" + +Deno.serve(async (request) => { + const pathname = new URL(request.url).pathname + switch (pathname) { + case "/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.", + session: session.session, + }) + } + default: { + if (pathname.startsWith("/api/auth/")) { + return await handlers.ALL(request) + } + return new Response("Not Found", { status: 404 }) + } + } +}) +``` + + + + diff --git a/docs/src/content/docs/integrations/tanstack-start.mdx b/docs/src/content/docs/integrations/tanstack-start.mdx new file mode 100644 index 00000000..00b2f4fa --- /dev/null +++ b/docs/src/content/docs/integrations/tanstack-start.mdx @@ -0,0 +1,125 @@ +--- +title: TanStack Start +description: Build your first authentication flow with Aura Auth and TanStack Start +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** in a **TanStack Start** application (integrating with Vinxi). + +## Overview + +TanStack Start server functions and API routes natively utilize the Web Standard `Request` and `Response` interfaces by wrapping the underlying Vinxi/Nitro engine. + + + + + +### Install Aura Auth + +Install the package in your TanStack project: + +```npm +npm install @aura-stack/auth +``` + + + + + +### Create an Auth Configuration + +Create your `auth.ts` instance inside your project server structure. + +```ts title="app/server/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + secret: process.env.AURA_AUTH_SECRET!, +}) +``` + + + + + +### Exposing Authentication API Routes + +TanStack Start generates API routes inside the `app/api` directory using Vinxi. You can create a catch-all route that proxies the standard Web Request into Aura Auth. + +```ts title="app/api/auth/[...auth].ts" lineNumbers +import { eventHandler, toWebRequest } from "@tanstack/start/server" +import { auth } from "../../server/auth" + +// Export the catch-all event handler +export default eventHandler((event) => { + const request = toWebRequest(event) + + // Pass it directly to Aura Auth's ALL handler + return auth.handlers.ALL(request) +}) +``` + + + + + +### Reading Session Securely + +You can verify the session securely via an SSR loader or server function by checking the incoming headers programmatically. + +```ts title="app/routes/protected.tsx" lineNumbers +import { createFileRoute, redirect } from "@tanstack/react-router" +import { createServerFn } from "@tanstack/start" +import { getWebRequest } from "@tanstack/start/server" +import { auth } from "../server/auth" + +const checkAuth = createServerFn("GET", async () => { + const request = getWebRequest() + const session = await auth.api.getSession(request) + + if (!session) { + throw redirect({ to: "/login" }) + } + + return session.user +}) + +export const Route = createFileRoute("/protected")({ + loader: async () => await checkAuth(), + component: ProtectedComponent, +}) + +function ProtectedComponent() { + const user = Route.useLoaderData() + return

Protected Dashboard for {user.name}

+} +``` + +
+ + + +### Using Client Methods + +To perform client-side sign-ins or logouts smoothly, initialize `createAuthClient` inside your frontend layout or components. + +```ts title="app/components/LoginButton.tsx" lineNumbers +import { createAuthClient } from "@aura-stack/auth/client" + +const authClient = createAuthClient({ + baseURL: "http://localhost:3000", + basePath: "/api/auth" +}) + +export function LoginButton() { + return ( + + ) +} +``` + + + +
diff --git a/docs/src/content/docs/integrations/vercel-edge-functions.mdx b/docs/src/content/docs/integrations/vercel-edge-functions.mdx new file mode 100644 index 00000000..d6cd0d90 --- /dev/null +++ b/docs/src/content/docs/integrations/vercel-edge-functions.mdx @@ -0,0 +1,114 @@ +--- +title: Vercel Edge Functions +description: Build your first authentication flow with Aura Auth and Vercel Edge Functions +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** directly with **Vercel Edge Functions**. + +## Overview + +Vercel Edge Functions run on the Edge Runtime, which supports web-standard APIs, including the `Request` and `Response` interfaces. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup + +Then use this guide to integrate Aura Auth with a Vercel Edge Function using best practices. + + + + + +### Project Structure + +```files +vercel-app +├── api +│ ├── auth +│ │ └── index.ts +│ ├── _auth.ts +│ └── index.ts +├── package.json +├── tsconfig.json +└── vercel.json +``` + + + + + +### Create an Auth Instance + +Create an `_auth.ts` file in your project to configure authentication. + +```ts title="api/_auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { handlers } = auth +``` + +`basePath` must match the route you expose in your Vercel app. + + + + + +### Integrate with Vercel Edge Functions + +Route auth traffic to a single edge function and pass the native `Request` directly to Aura Auth. + +```ts title="api/auth/index.ts" lineNumbers +import { handlers } from "@/api/_auth" + +export const GET = async (request: Request) => { + return await handlers.GET(request) +} + +export const POST = async (request: Request) => { + return await handlers.POST(request) +} + +export const PATCH = async (request: Request) => { + return await handlers.PATCH(request) +} +``` + + + + + +### Configure Vercel + +Create a `vercel.json` file to configure your Vercel deployment. This example rewrites auth routes to your edge function entrypoint. + +```json title="vercel.json" +{ + "outputDirectory": "dist", + "installCommand": "pnpm install --frozen-lockfile", + "functions": { + "api/**/*.ts": { + "maxDuration": 30 + } + }, + "rewrites": [ + { + "source": "/api/auth/:action", + "destination": "/api/auth" + }, + { + "source": "/api/auth/:action/:provider", + "destination": "/api/auth" + } + ] +} +``` + + + + diff --git a/docs/src/content/docs/meta.json b/docs/src/content/docs/meta.json index 20fdcb42..a8456ec4 100644 --- a/docs/src/content/docs/meta.json +++ b/docs/src/content/docs/meta.json @@ -8,6 +8,7 @@ "concepts", "configuration", "guides", + "integrations", "api-reference", "---Community---", "contributing" From c652b299aa51f3d4c8660dfaa9143daed907c746 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Thu, 2 Apr 2026 21:09:41 -0500 Subject: [PATCH 2/3] docs: refine integration docs --- apps/bun/src/index.ts | 4 +- apps/bun/tsconfig.json | 16 +- apps/hono/tsconfig.json | 12 +- apps/nextjs/app-router/src/@types/types.ts | 2 +- .../src/app/api/auth/[...aura]/route.ts | 2 +- apps/nextjs/app-router/src/contexts/auth.tsx | 16 +- .../src/lib/{client.ts => auth-client.ts} | 0 apps/nextjs/app-router/src/{ => lib}/auth.ts | 6 +- apps/nextjs/app-router/src/lib/server.ts | 2 +- apps/nuxt/shared/auth.ts | 4 +- apps/tanstack-start/src/routes/api/auth.$.ts | 3 + docs/src/app/global.css | 28 +- docs/src/content/docs/integrations/astro.mdx | 224 +++++++++-- docs/src/content/docs/integrations/bun.mdx | 119 ++++-- .../docs/integrations/cloudflare-workers.mdx | 84 +++- docs/src/content/docs/integrations/deno.mdx | 118 ++++-- docs/src/content/docs/integrations/elysia.mdx | 93 ++++- .../src/content/docs/integrations/express.mdx | 109 ++++-- docs/src/content/docs/integrations/hono.mdx | 96 ++++- docs/src/content/docs/integrations/meta.json | 3 +- .../docs/integrations/next-app-router.mdx | 310 +++++++++++++++ .../docs/integrations/next-pages-router.mdx | 337 ++++++++++++++++ docs/src/content/docs/integrations/next.mdx | 195 ---------- docs/src/content/docs/integrations/nuxt.mdx | 161 +++++--- docs/src/content/docs/integrations/oak.mdx | 96 +++-- .../docs/integrations/react-router.mdx | 272 +++++++++++-- .../integrations/supabase-edge-functions.mdx | 74 +++- .../docs/integrations/tanstack-start.mdx | 359 +++++++++++++++--- .../integrations/vercel-edge-functions.mdx | 77 +++- docs/src/content/docs/oauth/atlassian.mdx | 4 +- docs/src/content/docs/oauth/bitbucket.mdx | 2 +- docs/src/content/docs/oauth/dropbox.mdx | 2 +- docs/src/content/docs/oauth/github.mdx | 2 +- docs/src/content/docs/oauth/gitlab.mdx | 2 +- docs/src/content/docs/oauth/mailchimp.mdx | 4 +- docs/src/content/docs/oauth/notion.mdx | 2 +- docs/src/content/docs/oauth/pinterest.mdx | 2 +- docs/src/content/docs/oauth/strava.mdx | 4 +- docs/src/content/docs/oauth/twitch.mdx | 2 +- 39 files changed, 2225 insertions(+), 623 deletions(-) rename apps/nextjs/app-router/src/lib/{client.ts => auth-client.ts} (100%) rename apps/nextjs/app-router/src/{ => lib}/auth.ts (68%) create mode 100644 docs/src/content/docs/integrations/next-app-router.mdx create mode 100644 docs/src/content/docs/integrations/next-pages-router.mdx delete mode 100644 docs/src/content/docs/integrations/next.mdx diff --git a/apps/bun/src/index.ts b/apps/bun/src/index.ts index 2922d13c..b3996eef 100644 --- a/apps/bun/src/index.ts +++ b/apps/bun/src/index.ts @@ -11,7 +11,7 @@ Bun.serve({ }, "/api/protected": async (request) => { const session = await api.getSession({ - headers: request.headers, + headers: request.headers, }) if (!session.authenticated) { return Response.json( @@ -27,6 +27,6 @@ Bun.serve({ message: "You have access to this protected resource.", session, }) - }, + }, }, }) diff --git a/apps/bun/tsconfig.json b/apps/bun/tsconfig.json index 34c825d8..3b1b814d 100644 --- a/apps/bun/tsconfig.json +++ b/apps/bun/tsconfig.json @@ -1,10 +1,10 @@ { - "extends": "@aura-stack/tsconfig/bun.json", - "compilerOptions": { - "paths": { - "@/*": ["./src/*"], - }, - }, - "include": ["src"], - "exclude": ["dist", "node_modules"], + "extends": "@aura-stack/tsconfig/bun.json", + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "exclude": ["dist", "node_modules"] } diff --git a/apps/hono/tsconfig.json b/apps/hono/tsconfig.json index 8902be17..11145bc8 100644 --- a/apps/hono/tsconfig.json +++ b/apps/hono/tsconfig.json @@ -1,8 +1,8 @@ { - "extends": "@aura-stack/tsconfig/bun.json", - "compilerOptions": { - "jsxImportSource": "hono/jsx", - }, - "include": ["src"], - "exclude": ["dist", "node_modules"], + "extends": "@aura-stack/tsconfig/bun.json", + "compilerOptions": { + "jsxImportSource": "hono/jsx" + }, + "include": ["src"], + "exclude": ["dist", "node_modules"] } diff --git a/apps/nextjs/app-router/src/@types/types.ts b/apps/nextjs/app-router/src/@types/types.ts index 63d2ea67..5fad8d84 100644 --- a/apps/nextjs/app-router/src/@types/types.ts +++ b/apps/nextjs/app-router/src/@types/types.ts @@ -1,4 +1,4 @@ -import type { authClient } from "@/lib/client" +import type { authClient } from "@/lib/auth-client" import type { Session } from "@aura-stack/auth" export interface AuthContextValue { diff --git a/apps/nextjs/app-router/src/app/api/auth/[...aura]/route.ts b/apps/nextjs/app-router/src/app/api/auth/[...aura]/route.ts index 98793511..866b2beb 100644 --- a/apps/nextjs/app-router/src/app/api/auth/[...aura]/route.ts +++ b/apps/nextjs/app-router/src/app/api/auth/[...aura]/route.ts @@ -1,3 +1,3 @@ -import { handlers } from "@/auth" +import { handlers } from "@/lib/auth" export const { GET, POST } = handlers diff --git a/apps/nextjs/app-router/src/contexts/auth.tsx b/apps/nextjs/app-router/src/contexts/auth.tsx index 6dd325d6..d41e5d66 100644 --- a/apps/nextjs/app-router/src/contexts/auth.tsx +++ b/apps/nextjs/app-router/src/contexts/auth.tsx @@ -1,7 +1,7 @@ "use client" import { createContext, use, useState, useEffect } from "react" -import { authClient } from "@/lib/client" +import { authClient } from "@/lib/auth-client" import type { Session, LiteralUnion, BuiltInOAuthProvider, SignInOptions, SignOutOptions } from "@aura-stack/auth" import type { AuthContextValue } from "@/@types/types" import type { AuthProviderProps } from "@/@types/props" @@ -53,7 +53,19 @@ export const AuthProvider = ({ children, session: defaultSession }: AuthProvider }, [defaultSession]) return ( - {children} + + {children} + ) } diff --git a/apps/nextjs/app-router/src/lib/client.ts b/apps/nextjs/app-router/src/lib/auth-client.ts similarity index 100% rename from apps/nextjs/app-router/src/lib/client.ts rename to apps/nextjs/app-router/src/lib/auth-client.ts diff --git a/apps/nextjs/app-router/src/auth.ts b/apps/nextjs/app-router/src/lib/auth.ts similarity index 68% rename from apps/nextjs/app-router/src/auth.ts rename to apps/nextjs/app-router/src/lib/auth.ts index b5fdbf1b..7ef41eb5 100644 --- a/apps/nextjs/app-router/src/auth.ts +++ b/apps/nextjs/app-router/src/lib/auth.ts @@ -1,11 +1,11 @@ -import { type AuthInstance, createAuth } from "@aura-stack/auth" +import { createAuth } from "@aura-stack/auth" import { builtInOAuthProviders, type BuiltInOAuthProvider } from "@aura-stack/auth/oauth/index" export const oauth = Object.keys(builtInOAuthProviders) as BuiltInOAuthProvider[] export const providers = [builtInOAuthProviders.github(), builtInOAuthProviders.gitlab(), builtInOAuthProviders.bitbucket()] -export const { handlers, jose, api }: AuthInstance = createAuth({ +export const { handlers, jose, api } = createAuth({ oauth, basePath: "/api/auth", - trustedProxyHeaders: true, + baseURL: "http://localhost:3000", }) diff --git a/apps/nextjs/app-router/src/lib/server.ts b/apps/nextjs/app-router/src/lib/server.ts index 0eb23e6c..008ac01d 100644 --- a/apps/nextjs/app-router/src/lib/server.ts +++ b/apps/nextjs/app-router/src/lib/server.ts @@ -1,6 +1,6 @@ "use server" -import { api } from "@/auth" +import { api } from "@/lib/auth" import { redirect } from "next/navigation" import { cookies, headers } from "next/headers" import { isRedirectError } from "next/dist/client/components/redirect-error" diff --git a/apps/nuxt/shared/auth.ts b/apps/nuxt/shared/auth.ts index 3e3d0ebb..a6713420 100644 --- a/apps/nuxt/shared/auth.ts +++ b/apps/nuxt/shared/auth.ts @@ -1,9 +1,9 @@ -import { type AuthInstance, createAuth } from "@aura-stack/auth" +import { createAuth } from "@aura-stack/auth" import { builtInOAuthProviders, type BuiltInOAuthProvider } from "@aura-stack/auth/oauth/index" export const oauth = Object.keys(builtInOAuthProviders) as BuiltInOAuthProvider[] -export const { handlers, jose }: AuthInstance = createAuth({ +export const { handlers, jose } = createAuth({ oauth, basePath: "/api/auth", trustedProxyHeaders: true, diff --git a/apps/tanstack-start/src/routes/api/auth.$.ts b/apps/tanstack-start/src/routes/api/auth.$.ts index ed568a81..88ef0e37 100644 --- a/apps/tanstack-start/src/routes/api/auth.$.ts +++ b/apps/tanstack-start/src/routes/api/auth.$.ts @@ -10,6 +10,9 @@ export const Route = createFileRoute("/api/auth/$")({ POST: async ({ request }) => { return await handlers.POST(request) }, + PATCH: async ({ request }) => { + return await handlers.PATCH(request) + }, }, }, }) diff --git a/docs/src/app/global.css b/docs/src/app/global.css index 37174cd9..dc1b88d7 100644 --- a/docs/src/app/global.css +++ b/docs/src/app/global.css @@ -3,20 +3,16 @@ @import "fumadocs-ui/css/preset.css"; @theme { - --foreground: oklch(0.985 0 0); - --color-primary: oklch(0.97 0 0); - --color-primary-foreground: oklch(0.6 0.01 286.11); - --color-border: color-mix(in oklab, var(--color-white) 20%, transparent); - --breakpoint-base: 56.25rem; - --color-background: #000000; - --color-muted-foreground: color-mix( - in oklab, - var(--color-white) 60%, - transparent - ); - --breakpoint-xs: 540px; - --radius-2xl: 0rem; - --radius-xl: 0rem; - --radius-lg: 0rem; - --radius-md: 0rem; + --foreground: oklch(0.985 0 0); + --color-primary: oklch(0.97 0 0); + --color-primary-foreground: oklch(0.6 0.01 286.11); + --color-border: color-mix(in oklab, var(--color-white) 20%, transparent); + --breakpoint-base: 56.25rem; + --color-background: #000000; + --color-muted-foreground: color-mix(in oklab, var(--color-white) 60%, transparent); + --breakpoint-xs: 540px; + --radius-2xl: 0rem; + --radius-xl: 0rem; + --radius-lg: 0rem; + --radius-md: 0rem; } diff --git a/docs/src/content/docs/integrations/astro.mdx b/docs/src/content/docs/integrations/astro.mdx index ece816a4..60a80699 100644 --- a/docs/src/content/docs/integrations/astro.mdx +++ b/docs/src/content/docs/integrations/astro.mdx @@ -7,87 +7,249 @@ This guide walks you through creating a complete authentication flow using **Aur ## Overview -Astro's API endpoints (`pages/api/...`) natively receive and return Web Standard `Request` and `Response` objects, making it a perfect fit for Aura Auth's unified handlers. +Astro API routes receive and return Web Standard `Request` and `Response` objects, which makes Astro a natural fit for Aura Auth's unified handlers. + +--- + +## What You'll Build + +You will create a small Astro app with: + +- a shared `src/lib/auth.ts` server configuration +- a `src/pages/api/auth/[...auth].ts` route that forwards auth requests +- an optional `src/lib/auth-client.ts` browser client +- server and client examples for sign-in, session lookup, and sign-out + +--- -### Install Aura Auth +## Environment Setup -Install the package: +Create a `.env.local` file at the root of your project to store secrets securely. -```npm -npm install @aura-stack/auth +```bash title=".env.local" +# 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" ``` +Never commit your `.env.local` file to version control. Use a secret manager in production. + -### Create an Auth Configuration +## Setup Aura Auth -Set up your core configuration file anywhere securely accessible to your server endpoints. +### HTTP Handlers + +Set up your core configuration file in `src/lib/` so both server routes and client helpers can reuse it. ```ts title="src/auth.ts" import { createAuth } from "@aura-stack/auth" export const auth = createAuth({ oauth: ["github"], - secret: import.meta.env.AURA_AUTH_SECRET, + basePath: "/api/auth", }) + +export const { handlers, jose, api } = auth ``` +`basePath` must match the route mounted in `src/pages/api/auth/[...auth].ts`. `baseURL` should point to your local development server or deployed application URL. + +### Client API + +To use Aura Auth's client-side features, create an `auth-client.ts` file to initialize the client. + +```ts title="src/lib/auth-client.ts" +import { createAuthClient } from "@aura-stack/auth/client" + +export const authClient = createAuthClient({ + basePath: "/api/auth", + baseURL: "http://localhost:3000", +}) +``` + + + The `baseURL` should point to your server's URL, and `basePath` MUST match the path where your auth routes are mounted. + + +Keep the client and server values in sync. If you move the auth route, update both `basePath` values together. + -### Integrate with Astro's API routes +## Mount HTTP Handlers -Create a catch-all route under your API directory `src/pages/api/auth/[...auth].ts`. We export the `ALL` handler to automatically take care of GET, POST, and other HTTP methods. +Create a catch-all route under `src/pages/api/auth/[...auth].ts`. The route below forwards each HTTP method to the corresponding Aura Auth handler. ```ts title="src/pages/api/auth/[...auth].ts" lineNumbers -import { auth } from "../../../auth" +import { handlers } from "@/lib/auth" import type { APIRoute } from "astro" -export const ALL: APIRoute = ({ request }) => { - return auth.handlers.ALL(request) +export const GET: APIRoute = async ({ request }) => { + return await handlers.GET(request) +} + +export const POST: APIRoute = async ({ request }) => { + return await handlers.POST(request) +} + +export const PATCH: APIRoute = async ({ request }) => { + return await handlers.PATCH(request) } ``` - - Ensure your `basePath` option in `createAuth` matches the actual route (`/api/auth`) if you place it outside the standard root - `/auth` path. - +Ensure your `basePath` option in `createAuth` matches the actual route (`/api/auth`). + +This route can be extended with additional methods if your auth flow needs them later. -### Access the Session in Astro Components +## Usage + +Use server-side code when you want to protect a page before it renders, and use the client helper when you need interactive buttons or session-aware UI. + +### Server Side Rendering (SSR) -You can retrieve the session during Server-Side Rendering (SSR) directly in your Astro component's frontmatter! +#### Get Session -```astro title="src/pages/dashboard.astro" lineNumbers +```astro title="src/pages/index.astro" lineNumbers --- -import { auth } from "../auth"; +import { api } from "@/lib/auth" -// Pass Astro.request to interact natively with headers -const session = await auth.api.getSession(Astro.request); +const result = await api.getSession({ + headers: Astro.request.headers, +}) -if (!session) { - return Astro.redirect("/login"); +if (!result.authenticated) { + return Astro.redirect("/login") } + +const session = result.session --- - - -

Welcome, {session.user.name}!

- Avatar - - +

Welcome back, {session.user?.name}

+

Email: {session.user?.email}

``` +This is the recommended pattern for protected pages: check authentication on the server and only render private UI when a session is present. + +#### Sign-Out + +```astro title="src/pages/index.astro" lineNumbers +--- +import { api } from "@/lib/auth" + +const signOutAction = async () => { + const response = await api.signOut({ + headers: Astro.request.headers, + }) + + return response +} +--- + +
+ +
+``` + +If you prefer a client-only interaction, call `authClient.signOut()` from a client component instead. + +### Client Side Rendering (CSR) + +#### Sign-In + +```tsx title="src/components/sign-in-button.tsx" lineNumbers +import { authClient } from "@/lib/auth-client" + +export default function SignInButton() { + const handleSignIn = () => { + void authClient.signIn("github", { + redirectTo: "/dashboard", + }) + } + + return +} +``` + +Use a client component for one-click auth entry points or custom UI that cannot be expressed as a server action. + +#### Get Session + +```tsx title="src/components/user-profile.tsx" lineNumbers +import { useEffect, useState } from "react" +import { authClient } from "@/lib/auth-client" + +export default function UserProfile() { + const [session, setSession] = useState(null) + + useEffect(() => { + const fetchSession = async () => { + const { session } = await authClient.getSession() + setSession(session) + } + fetchSession() + }, []) + + if (!session) return

Loading...

+ + return ( +
+

Welcome back, {session.user?.name}

+

Email: {session.user?.email}

+
+ ) +} +``` + +This approach is useful for nav bars, avatars, and other session-aware UI that updates after hydration. + +#### Sign-Out + +```tsx title="src/components/sign-out-button.tsx" lineNumbers +import { authClient } from "@/lib/auth-client" + +export default function SignOutButton() { + const handleSignOut = async () => { + await authClient.signOut() + } + + return +} +``` + +Client-side sign-out is best for interactive controls inside menus or profile popovers. +
+ +--- + +## Common Pitfalls + +- **Keep `basePath` aligned with the route segment**. If your auth endpoint is `/api/auth/*`, the auth config should use `basePath: "/api/auth"`. +- **Keep the shared auth module in one place**. Import `src/lib/auth.ts` from both the API route and the client helper. +- **Check authentication before rendering private UI**. Use the server-side `authenticated` flag to protect pages. +- **Use `Astro.request.headers` when calling server helpers**. That gives Aura Auth access to the cookies it needs to read the session. + +--- + +## Resources + +- [Astro Documentation](https://docs.astro.build/) +- [Aura Auth Documentation](/quick-start) +- [Astro Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/astro) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/bun.mdx b/docs/src/content/docs/integrations/bun.mdx index 9c8f07b2..8d09ac84 100644 --- a/docs/src/content/docs/integrations/bun.mdx +++ b/docs/src/content/docs/integrations/bun.mdx @@ -7,20 +7,33 @@ This guide walks you through creating a complete authentication flow using **Aur ## Overview -Aura Auth and Bun both follow the web-standard `Request` and `Response` interfaces for high-performance HTTP handling. This means Aura Auth works out of the box with `Bun.serve`, with no external adapters or frameworks required. +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](/docs/quick-start) to create your Aura Auth instance - [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Bun Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/bun) 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.ts` server configuration +- a `src/index.ts` entry point that mounts the auth handlers +- a simple protected route example that validates the session before responding + +--- + -### Project Structure +## Project Structure ```files bun-app @@ -28,19 +41,34 @@ bun-app │ ├── lib │ │ └── auth.ts │ └── index.ts -├── tsconfig.json -└── package.json +└── .env.local +``` + + + + + +## Environment Setup + +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" ``` +Never commit your `.env.local` file to version control. Use a secret manager in production. + -### Create an Auth Instance +## Setup Aura Auth -Create `auth.ts` in `src/lib/` and configure the OAuth providers and options for your Aura Auth instance. +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. -```ts title="lib/auth.ts" +```ts title="src/lib/auth.ts" import { createAuth } from "@aura-stack/auth" export const auth = createAuth({ @@ -48,26 +76,30 @@ export const auth = createAuth({ basePath: "/api/auth", }) -export const { handlers } = auth +export const { handlers, jose, api } = auth ``` -`basePath` must match the route you expose in Bun.serve. +`basePath` 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. -### Integrate with Bun.serve +## Mount HTTP Handlers -Define auth routes directly in `Bun.serve`. Any request matching `/api/auth/*` is handled by `handlers.ALL`. +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. -```ts title="index.ts" lineNumbers +```ts title="src/index.ts" lineNumbers import { handlers } from "@/lib/auth" Bun.serve({ port: 3000, - routes: { - "/api/auth/*": handlers.ALL, + 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 }) }, }) @@ -78,42 +110,67 @@ console.log("Bun server running on http://localhost:3000") -### Protecting Routes +## Usage + +### Get Session -Bun does not include framework-style middleware, but you can protect routes with a small helper-style handler that validates the current session. +Bun does not include framework-style middleware, but you can protect routes with a simple handler that validates the session before responding. -```ts title="index.ts" lineNumbers -import { auth, handlers } from "@/lib/auth" +```ts title="src/index.ts" lineNumbers +import { api, handlers } from "@/lib/auth" Bun.serve({ port: 3000, - routes: { - "/api/auth/*": handlers.ALL, - "/api/protected": async (request) => { - const session = await auth.api.getSession({ + 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({ error: "Unauthorized", message: "Active session required." }, { status: 401 }) } return Response.json({ message: "You have access to this protected resource.", - session, + 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 `basePath` aligned with your route segment**. If your handler route is `/api/auth/*`, `basePath` should 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.authenticated` before exposing sensitive data. +- **Use TypeScript for safer session access**. Type-guard your session object to avoid runtime errors when accessing user fields. + +--- + +## Resources + +- [Bun Documentation](https://bun.sh/docs) +- [Aura Auth Documentation](/quick-start) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/cloudflare-workers.mdx b/docs/src/content/docs/integrations/cloudflare-workers.mdx index 3e615b3b..fb9b9db3 100644 --- a/docs/src/content/docs/integrations/cloudflare-workers.mdx +++ b/docs/src/content/docs/integrations/cloudflare-workers.mdx @@ -7,20 +7,34 @@ This guide walks you through creating a complete authentication flow using **Aur ## Overview -Cloudflare Workers use the Fetch API (`Request` and `Response`), which matches Aura Auth's framework-agnostic design. +Cloudflare Workers use the Fetch API (`Request` and `Response`), which matches Aura Auth's framework-agnostic design. That makes the integration simple: you can mount Aura Auth directly in the worker `fetch` handler and keep your auth logic in one shared module. Before continuing, complete the installation and initial setup: - [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance - [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Cloudflare Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/cloudflare) for a fully working example Then use this guide to integrate Aura Auth with a Cloudflare Worker using best practices. +--- + +## What You'll Build + +You will create a small Cloudflare Worker app with: + +- a shared `src/lib/auth.ts` server configuration +- a `src/index.ts` worker entry point that mounts the auth handlers +- Cloudflare secret bindings for auth credentials +- a worker example that routes auth requests and returns 404 for everything else + +--- + -### Project Structure +## Project Structure ```files cloudflare-app @@ -28,8 +42,7 @@ cloudflare-app │ ├── lib │ │ └── auth.ts │ └── index.ts -├── tsconfig.json -├── package.json +├── .env.local └── wrangler.jsonc ``` @@ -37,10 +50,22 @@ cloudflare-app -### Secret Variables Setup +## Environment Setup + +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" +``` + +Never commit your `.env.local` file to version control. Use a secret manager in production. Using the `wrangler` CLI or the Cloudflare dashboard, add the required secret environment variables. Workers read secrets from the `env` argument rather than `process.env`. +Cloudflare Workers also support secret bindings in the dashboard, which is the preferred option for production deployments. + ```bash npx wrangler secret put AURA_AUTH_SECRET npx wrangler secret put AURA_AUTH_SALT @@ -58,10 +83,33 @@ wrangler types -### Initialize Aura Auth per Request +## Setup Aura Auth + +Set up your `auth.ts` file in `src/lib/` and configure Aura Auth for your Cloudflare Worker. + +```ts title="src/lib/auth.ts" +import { createAuth } from "npm:@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { handlers, jose, api } = auth +``` + +`basePath` must match the route you expose in your worker. If the route changes, update the auth config and handler together. + + + + + +## Mount HTTP Handlers Because Workers pass environment variables into the `fetch` execution context, keep your auth setup in a separate module and route `/api/auth/*` requests to `handlers.ALL`. +The worker below delegates only auth requests to Aura Auth and returns a 404 for everything else. + ```ts title="src/index.ts" lineNumbers import { handlers } from "@/lib/auth" @@ -76,16 +124,28 @@ export default { } satisfies ExportedHandler ``` +Use this pattern when you want a single worker to handle both auth endpoints and a small number of custom routes. + - + + +--- -### Securing the Worker edge cases +## Common Pitfalls -Because edge workers execute globally across multiple locations, standard Node.js APIs are not always available. +- **Keep `basePath` aligned with the worker route**. If your auth endpoint is `/api/auth/*`, the auth config should use `basePath: "/api/auth"`. +- **Use Cloudflare secret bindings in production**. Workers should read credentials from `env`, not from `process.env`. +- **Keep the auth logic in one module**. Import `src/lib/auth.ts` from your worker entry point so the handlers stay shared and consistent. +- **Return a 404 for non-auth routes**. That keeps the worker behavior explicit and easier to debug. -Aura Auth is runtime-agnostic and uses the Web Crypto API and web standards, so it works without `node:crypto` imports in your Worker deployment. +--- - +## Resources - +- [Cloudflare Workers Documentation](https://developers.cloudflare.com/workers/) +- [Aura Auth Documentation](/quick-start) +- [Cloudflare Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/cloudflare) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/deno.mdx b/docs/src/content/docs/integrations/deno.mdx index e83a008d..ccd6856e 100644 --- a/docs/src/content/docs/integrations/deno.mdx +++ b/docs/src/content/docs/integrations/deno.mdx @@ -13,14 +13,28 @@ Before continuing, complete the installation and initial setup: - [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance - [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Deno Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/deno) for a fully working example Then use this guide to integrate Aura Auth with a Deno server using best practices. +--- + +## What You'll Build + +You will create a small Deno app with: + +- a shared `src/lib/auth.ts` server configuration +- a `src/index.ts` entry point that mounts the auth handlers +- a protected route example that validates the current session before responding +- a clear route setup that keeps auth and protected endpoints separate + +--- + -### Project Structure +## Project Structure ```files deno-app @@ -28,6 +42,7 @@ deno-app │ ├── lib │ │ └── auth.ts │ └── index.ts +├── .env.local └── deno.json ``` @@ -35,11 +50,27 @@ deno-app -### Create an Auth Instance +## Environment Setup -Create `auth.ts` in `src/lib/` and configure the OAuth providers and options for your Aura Auth instance. +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" +``` -```ts title="lib/auth.ts" +Never commit your `.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 shared helpers used by the Deno server. + +```ts title="src/lib/auth.ts" import { createAuth } from "npm:@aura-stack/auth" export const auth = createAuth({ @@ -47,16 +78,16 @@ export const auth = createAuth({ basePath: "/api/auth", }) -export const { handlers } = auth +export const { handlers, jose, api } = auth ``` -`basePath` must match the route you expose in Deno.serve. +`basePath` must match the route you expose in `Deno.serve`. `baseURL` is optional for local development but should be set to your deployed domain in production. -### Integrate with Deno.serve +## Mount HTTP Handlers Define auth routes directly in `Deno.serve`. Any request matching `/api/auth/*` is handled by `handlers.ALL`. @@ -74,11 +105,15 @@ Deno.serve({ port: 3000 }, async (request) => { }) ``` +This keeps auth requests isolated from the rest of your application routes. + -### Protecting Routes +## Usage + +### Get Session Deno does not include framework-style middleware, but you can protect routes with a small helper-style handler that validates the current session. @@ -88,50 +123,51 @@ import { auth, handlers } from "./lib/auth.ts" Deno.serve({ port: 3000 }, async (request) => { const pathname = new URL(request.url).pathname - switch (pathname) { - case "/api/protected": { - const session = await auth.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.", - session, - }) - } + if (pathname.startsWith("/api/auth/")) { + return await handlers.ALL(request) + } - default: { - if (pathname.startsWith("/api/auth/")) { - return await handlers.ALL(request) - } + if (pathname === "/api/protected") { + const session = await auth.api.getSession({ + headers: request.headers, + }) - return new Response("Not Found", { status: 404 }) + 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 }) }) ``` +This pattern works well for small APIs or server-rendered entry points. For larger apps, consider splitting the auth route and protected routes into separate modules. + - + -### Run the App +--- -Deno enforces security by default. Make sure you allow reading from the environment and receiving network connections. +## Common Pitfalls -```bash -deno run --allow-net --allow-env src/index.ts -``` +- **Keep `basePath` aligned with your route logic**. If your auth route is `/api/auth/*`, `basePath` should be `/api/auth`. +- **Always pass request headers to `auth.api.getSession()`**. The session lookup needs headers so Aura Auth can read cookies. +- **Check `session.authenticated` before exposing private data**. Use the authenticated flag to guard sensitive responses. +- **Keep the auth route and protected route separate**. That makes the server behavior easier to reason about and debug. - +--- - +## Resources + +- [Deno Documentation](https://docs.deno.com/) +- [Aura Auth Documentation](/quick-start) +- [Deno Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/deno) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/elysia.mdx b/docs/src/content/docs/integrations/elysia.mdx index 409f220a..5f8443e2 100644 --- a/docs/src/content/docs/integrations/elysia.mdx +++ b/docs/src/content/docs/integrations/elysia.mdx @@ -7,20 +7,34 @@ This guide walks you through creating a complete authentication flow using **Aur ## Overview -Aura Auth and Elysia, an ergonomic web framework for Bun, both follow the web-standard `Request` and `Response` interfaces for high-performance HTTP handling. This means Aura Auth works out of the box with Elysia, with no external adapters or frameworks required. +Aura Auth and Elysia, an ergonomic web framework for 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 Elysia, with no external adapters or frameworks required. Before continuing, complete the installation and initial setup: - [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance - [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Elysia Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/elysia) for a fully working example Then use this guide to integrate Aura Auth with an Elysia server using best practices. +--- + +## What You'll Build + +You will create a small Elysia app with: + +- a shared `src/lib/auth.ts` server configuration +- a `src/index.ts` entry point that mounts the auth handlers +- a `src/plugins/with-auth.ts` plugin that adds session data to the context +- a protected route example that validates the session before responding + +--- + -### Project Structure +## Project Structure ```files elysia-app @@ -30,19 +44,34 @@ elysia-app │ ├── plugins │ │ └── with-auth.ts │ └── index.ts -├── tsconfig.json -└── package.json +└── .env.local ``` -### Create an Auth Instance +## Environment Setup + +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" +``` + +Never commit your `.env.local` file to version control. Use a secret manager in production. + + + + -Create `auth.ts` in `src/lib/` and configure the OAuth providers and options for your Aura Auth instance. +## Setup Aura Auth -```ts title="lib/auth.ts" lineNumbers +Create `auth.ts` in `src/lib/` to configure Aura Auth and export the shared handlers used by the server and plugins. + +```ts title="src/lib/auth.ts" lineNumbers import { createAuth } from "@aura-stack/auth" export const auth = createAuth({ @@ -50,20 +79,20 @@ export const auth = createAuth({ basePath: "/api/auth", }) -export const { handlers } = auth +export const { handlers, jose, api } = auth ``` -`basePath` must match the route you expose in Elysia. +`basePath` must match the route you expose in Elysia. If your server changes, update both the route and the auth config together. -### Integrate with Elysia +## Mount HTTP Handlers -Mount auth handlers to process all traffic directed to the `/api/auth/*` path in your Elysia app: +Mount auth handlers to process all traffic directed to the `/api/auth/*` path in your Elysia app. Elysia passes standard Web `Request` objects, so the shared handler can be called directly. -```ts title="index.ts" lineNumbers +```ts title="src/index.ts" lineNumbers import { Elysia } from "elysia" import { auth } from "@/lib/auth" @@ -76,13 +105,19 @@ app.all("/api/auth/*", (ctx) => { app.listen(3000) ``` +This keeps all auth endpoints in one place and leaves the rest of your routes free to use the same `auth` instance. + -### Add Elysia Plugin for Session Management +## Usage + +Use a plugin when you want session data to be available across multiple protected routes. That keeps your auth checks consistent and avoids repeating the same session lookup in every handler. + +### Plugin -```ts title="plugins/with-auth.ts" lineNumbers +```ts title="src/plugins/with-auth.ts" lineNumbers import { Elysia } from "elysia" import { auth } from "@/lib/auth" @@ -103,15 +138,17 @@ export const withAuthPlugin = new Elysia({ name: "with-auth" }) .get("/api/auth/me", ({ session }) => session) ``` +The plugin returns `session: null` when the request is unauthenticated, which keeps downstream routes simple and predictable. + -### Protecting Routes +### Get Session -Use the plugin in your app and protect routes by checking for an active session: +Use the plugin in your app and protect routes by checking for an active session before returning private data. -```ts title="index.ts" lineNumbers +```ts title="src/index.ts" lineNumbers import { Elysia } from "elysia" import { auth } from "@/lib/auth" import { withAuthPlugin } from "@/plugins/with-auth" @@ -142,6 +179,28 @@ app.use(withAuthPlugin).get("/api/protected", (ctx) => { app.listen(3000) ``` +This pattern works well for dashboard pages, account APIs, and any route that should never return private data without a valid session. + + +--- + +## Common Pitfalls + +- **Keep `basePath` aligned with the route you mount**. If your auth endpoint is `/api/auth/*`, the auth config should use `basePath: "/api/auth"`. +- **Use the same auth instance everywhere**. Import `src/lib/auth.ts` from the server entry point and from plugins so there is one source of truth. +- **Return `session: null` for anonymous requests**. That keeps downstream route handlers simple and avoids repeated null checks. +- **Protect private routes before sending the response**. Check the session first, then return the private payload only when authentication succeeds. + +--- + +## Resources + +- [Elysia Documentation](https://elysiajs.com/) +- [Aura Auth Documentation](/quick-start) +- [Elysia Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/elysia) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/express.mdx b/docs/src/content/docs/integrations/express.mdx index 6196b31c..c7801747 100644 --- a/docs/src/content/docs/integrations/express.mdx +++ b/docs/src/content/docs/integrations/express.mdx @@ -7,20 +7,34 @@ This guide walks you through creating a complete authentication flow using **Aur ## Overview -Express is built around Node.js `IncomingMessage` and `ServerResponse` streams rather than modern web-standard `Request` and `Response` objects. It requires a small adapter to bridge Express and Aura Auth's web-standard handlers. +Express is built around Node.js `IncomingMessage` and `ServerResponse` streams rather than modern web-standard `Request` and `Response` objects. That means it needs a small adapter to bridge Express and Aura Auth's web-standard handlers. Before continuing, complete the installation and initial setup: - [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance - [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Express Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/express) for a fully working example Then use this guide to integrate Aura Auth with an Express server using best practices. +--- + +## What You'll Build + +You will create a small Express app with: + +- a shared `src/lib/auth.ts` server configuration +- a `src/lib/handler.ts` adapter that bridges Express and Aura Auth +- a `src/middlewares/verify-session.ts` middleware for protected routes +- a `src/types.d.ts` augmentation for `res.locals.session` + +--- + -### Project Structure +## Project Structure ```files express-app @@ -40,11 +54,27 @@ express-app -### Create an Auth Instance +## Environment Setup + +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" +``` -Create an `auth.ts` file in your project to configure authentication. +Never commit your `.env.local` file to version control. Use a secret manager in production. -```ts title="lib/auth.ts" + + + + +## Setup Aura Auth + +Create an `auth.ts` file in `src/lib/` to configure authentication and export the shared handlers used by the adapter and middleware. + +```ts title="src/lib/auth.ts" import { createAuth } from "@aura-stack/auth" export const auth = createAuth({ @@ -52,20 +82,22 @@ export const auth = createAuth({ basePath: "/api/auth", }) -export const { handlers } = auth +export const { handlers, api } = auth ``` -`basePath` must match the route you expose in your Express app. +`basePath` must match the route you expose in your Express app. If the route changes, update the auth config and adapter together. -### Handler Adapter +## Mount HTTP Handlers Because Express uses `IncomingMessage` and `ServerResponse`, create an adapter that converts them into the web-standard `Request` and `Response` objects Aura Auth expects. -```ts title="lib/handler.ts" lineNumbers +The adapter below translates the incoming request into a Web `Request`, then translates the Aura Auth `Response` back into Express. + +```ts title="src/lib/handler.ts" lineNumbers import { handlers } from "@/lib/auth.js" import type { Request, Response } from "express" @@ -77,7 +109,7 @@ const splitSetCookieHeaderValue = (value: string): string[] => { } /** - * Convert an Express Request to a Web API Request so it can be handled + * Convert an Express request to a Web API Request so it can be handled * by the framework-agnostic Aura Auth handlers. */ export const toWebRequest = (req: Request): globalThis.Request => { @@ -110,7 +142,7 @@ export const toWebRequest = (req: Request): globalThis.Request => { } /** - * Forward the Web API Response back to the Express Response. + * Forward the Web API Response back to the Express response. * Handles redirects, multiple Set-Cookie headers, and JSON/text bodies. */ export const toExpressResponse = async (webResponse: globalThis.Response, res: Response) => { @@ -141,7 +173,7 @@ export const toExpressResponse = async (webResponse: globalThis.Response, res: R } /** - * Express middleware that bridges Aura Auth Web-API handlers to Express. + * Express middleware that bridges Aura Auth Web API handlers to Express. * Mount this on the `basePath` configured in `createAuth()` (default: `/api/auth`). */ export const toExpressHandler = async (req: Request, res: Response) => { @@ -150,18 +182,11 @@ export const toExpressHandler = async (req: Request, res: Response) => { } ``` - - - - -### Integrate with Express - -Mount the Aura Auth handlers inside your Express app using the Web Standard adapter: +Mount the Aura Auth handlers inside your Express app using the Web Standard adapter. -```ts title="index.ts" lineNumbers +```ts title="src/index.ts" lineNumbers import express, { type Express } from "express" import { toExpressHandler } from "@/lib/handler.js" -import { verifySession } from "@/middlewares/verify-session.js" const app: Express = express() @@ -175,15 +200,19 @@ app.listen(3000, () => { }) ``` +Use this route for all auth methods, including sign-in, sign-out, session lookups, and provider callbacks. + +## Usage + ### Middleware Middlewares are a common pattern in Express apps for protecting routes. You can create a middleware that checks for an active session before allowing access to protected routes. -```ts title="middlewares/verify-session.ts" lineNumbers +```ts title="src/middlewares/verify-session.ts" lineNumbers import { auth } from "@/lib/auth.js" import { toWebRequest } from "@/lib/handler.js" import type { Request, Response, NextFunction } from "express" @@ -206,8 +235,8 @@ export const verifySession = async (req: Request, res: Response, next: NextFunct Express doesn't infer the `Locals` type automatically, so extend it to include the session: -```ts title="types.d.ts" lineNumbers -import { Session } from "@aura-stack/auth" +```ts title="src/types.d.ts" lineNumbers +import type { Session } from "@aura-stack/auth" declare global { namespace Express { @@ -218,15 +247,11 @@ declare global { } ``` - - - - -### Access the Session +### Get Session -To access the active session in your protected Express routes, you can use the `auth.api.getSession` method: +To access the active session in your protected Express routes, use the `verifySession` middleware and read `res.locals.session`. -```ts title="index.ts" lineNumbers +```ts title="src/index.ts" lineNumbers import express, { type Express } from "express" import { toExpressHandler } from "@/lib/handler.js" import { verifySession } from "@/middlewares/verify-session.js" @@ -251,6 +276,28 @@ app.listen(3000, () => { }) ``` +This pattern keeps the session lookup centralized and makes protected route logic easy to reuse across the app. + + +--- + +## Common Pitfalls + +- **Keep `basePath` aligned with the mounted auth route**. If your auth endpoint is `/api/auth/*`, the auth config should use `basePath: "/api/auth"`. +- **Always convert Express headers before calling Aura Auth**. The Web API session helper expects standard request headers. +- **Use `session.authenticated` as the guard**. Check that flag before exposing private data. +- **Keep the adapter and middleware separate**. The adapter should only translate request and response objects, while the middleware should only enforce access. + +--- + +## Resources + +- [Express Documentation](https://expressjs.com/) +- [Aura Auth Documentation](/quick-start) +- [Express Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/express) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/hono.mdx b/docs/src/content/docs/integrations/hono.mdx index 675b2379..489158b3 100644 --- a/docs/src/content/docs/integrations/hono.mdx +++ b/docs/src/content/docs/integrations/hono.mdx @@ -7,20 +7,34 @@ This guide walks you through creating a complete authentication flow using **Aur ## Overview -Hono is built on web standards (`Request` and `Response`), which makes integrating Aura Auth incredibly simple and elegant. You can use the new `ALL` handler to cover all authentication HTTP methods in a single route. +Hono is built on web standards (`Request` and `Response`), which makes integrating Aura Auth straightforward. You can use the `ALL` handler to cover all authentication HTTP methods in a single route. Before continuing, complete the installation and initial setup: - [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance - [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Hono Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/hono) for a fully working example -Then use this guide to integrate Aura Auth with an Hono using best practices. +Then use this guide to integrate Aura Auth with Hono using best practices. + +--- + +## What You'll Build + +You will create a small Hono app with: + +- a shared `src/lib/auth.ts` server configuration +- a `src/index.ts` entry point that mounts the auth handlers +- a `src/middlewares/with-auth.ts` middleware that adds session data to the context +- a protected route example that validates the session before responding + +--- -### Project Structure +## Project Structure ```files hono-app @@ -30,39 +44,55 @@ hono-app │ ├── middlewares │ │ └── with-auth.ts │ └── index.ts -├── tsconfig.json -└── package.json +└── .env.local ``` -### Create an Auth Instance +## Environment Setup + +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" +``` + +Never commit your `.env.local` file to version control. Use a secret manager in production. + + + + -Create an `auth.ts` file in your project to configure authentication. +## Setup Aura Auth -```ts title="lib/auth.ts" +Create an `auth.ts` file in `src/lib/` to configure authentication and export the shared helpers used by the app and middleware. + +```ts title="src/lib/auth.ts" import { createAuth } from "@aura-stack/auth" export const auth = createAuth({ oauth: ["github"], + basePath: "/api/auth", }) export const { handlers, api, jose } = auth ``` -`basePath` must match the route you expose in your Hono app. +`basePath` must match the route you expose in your Hono app. If the route changes, update the auth config and route handler together. -### Integrate with Hono +## Mount HTTP Handlers -Mount the Aura Auth handlers using a wildcard route `/*` under your `/api/auth` subpath. You can pass `c.req.raw`, which is the native Web Standard `Request` object. +Mount the Aura Auth handlers using a wildcard route under your `/api/auth` subpath. Hono passes the native Web Standard `Request` object through `c.req.raw`, so the handler can delegate directly. -```ts title="index.ts" lineNumbers +```ts title="src/index.ts" lineNumbers import { Hono } from "hono" import { handlers } from "@/lib/auth" @@ -75,15 +105,19 @@ app.all("/api/auth/*", async (ctx) => { export default app ``` +This keeps all auth endpoints in one place and leaves the rest of your routes free to use the same auth instance. + +## Usage + ### Middleware -Middleware is a powerful way to protect your routes and access session data across your app. Create a `with-auth.ts` file in `src/middlewares`: +Middleware is a powerful way to protect your routes and access session data across your app. Create a `with-auth.ts` file in `src/middlewares`. -```ts title="middlewares/with-auth.ts" lineNumbers +```ts title="src/middlewares/with-auth.ts" lineNumbers import { api } from "@/lib/auth" import { createMiddleware } from "hono/factory" import type { Session } from "@aura-stack/auth" @@ -92,7 +126,7 @@ import type { Session } from "@aura-stack/auth" * Type definition for Hono's Context Variables to include the session. */ export type AuthVariables = { - session: Session + session: Session | null } export const withAuth = createMiddleware<{ Variables: AuthVariables }>(async (ctx, next) => { @@ -111,16 +145,16 @@ export const withAuth = createMiddleware<{ Variables: AuthVariables }>(async (ct }) ``` - +The plugin returns session data only when the request is authenticated, which keeps downstream routes simple and predictable. - +### Get Session -### Protecting Routes +Use the middleware in your app and protect routes by checking for an active session before allowing access. -```ts title="index.ts" lineNumbers +```ts title="src/index.ts" lineNumbers import { Hono } from "hono" import { handlers } from "@/lib/auth" -import { type AuthVariables, withAuth } from "@/middleware/with-auth" +import { type AuthVariables, withAuth } from "@/middlewares/with-auth" const app = new Hono<{ Variables: AuthVariables }>() @@ -143,6 +177,28 @@ app.get("/api/protected", withAuth, (ctx) => { export default app ``` +This pattern works well for dashboards, account endpoints, and any route that should not return private data unless the request is authenticated. + + +--- + +## Common Pitfalls + +- **Keep `basePath` aligned with your auth route**. If your auth endpoint is `/api/auth/*`, the auth config should use `basePath: "/api/auth"`. +- **Import the middleware from the correct folder**. The shared middleware lives in `src/middlewares/with-auth.ts`. +- **Use `session.authenticated` as the guard**. Check that flag before exposing private data. +- **Keep the auth handler and route logic separate**. The auth route should only forward requests to Aura Auth. + +--- + +## Resources + +- [Hono Documentation](https://hono.dev/) +- [Aura Auth Documentation](/quick-start) +- [Hono Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/hono) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/meta.json b/docs/src/content/docs/integrations/meta.json index f5f2e778..17af30b0 100644 --- a/docs/src/content/docs/integrations/meta.json +++ b/docs/src/content/docs/integrations/meta.json @@ -3,7 +3,8 @@ "pages": [ "---Frontend---", "astro", - "next", + "next-app-router", + "next-pages-router", "nuxt", "react-router", "tanstack-start", diff --git a/docs/src/content/docs/integrations/next-app-router.mdx b/docs/src/content/docs/integrations/next-app-router.mdx new file mode 100644 index 00000000..c06f6f89 --- /dev/null +++ b/docs/src/content/docs/integrations/next-app-router.mdx @@ -0,0 +1,310 @@ +--- +title: Next.js (App Router) +description: Integrate Aura Auth and Next.js App Router +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** directly with the Next.js App Router's native Route Handlers and Server Actions. + +## Overview + +Aura Auth and Next.js App Router both follow the web-standard `Request` and `Response` interfaces for high-performance HTTP handling. That makes the integration straightforward: you can mount Aura Auth directly in Route Handlers and use the same `api` object in Server Components and Server Actions. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Next.js Installation Guide](https://nextjs.org/docs/app/getting-started/installation) to set up your Next.js project + +Then use this guide to integrate Aura Auth with a Next.js application using best practices. + +--- + +## What You'll Build + +You will create a small Next.js App Router setup with: + +- a shared `src/lib/auth.ts` server configuration +- an `app/api/auth/[...aura]/route.ts` handler +- an optional `src/lib/auth-client.ts` browser client +- server and client examples for sign-in, session lookup, and sign-out + +--- + + + + + +## Project Structure + +```files +next-app +├── src +│ ├── app +│ │ └── api +│ │ │ └── auth +│ │ │ │ └── [...aura] +│ │ │ │ │ └── route.ts +│ ├── lib +│ │ ├── auth.ts +│ │ └── auth-client.ts +└── .env.local +``` + + + + + +## Environment Setup + +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" +``` + +Never commit your `.env.local` file to version control. Use a secret manager in production. + + + + + +## Setup Aura Auth + +### HTTP Handlers + +Create an `auth.ts` file in `src/lib/` to configure authentication and export the helpers used by both route handlers and server utilities. + +```ts title="lib/auth.ts" lineNumbers +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", + baseURL: "http://localhost:3000", +}) + +export const { handlers, jose, api } = auth +``` + +`basePath` must match the route mounted in `app/api/auth/[...aura]/route.ts`. `baseURL` should point to your local development server or deployed application URL. + +### Client API + +To use Aura Auth's client-side features, create an `auth-client.ts` file to initialize the client. + +```ts title="lib/auth-client.ts" +import { createAuthClient } from "@aura-stack/auth/client" + +export const authClient = createAuthClient({ + basePath: "/api/auth", + baseURL: "http://localhost:3000", +}) +``` + + + The `baseURL` should point to your server's URL, and `basePath` MUST match the path where your auth routes are mounted. + + + + + + +## Mount HTTP Handlers + +Create a catch-all route to handle all authentication endpoints dynamically. Next.js App Router uses standard Web `Request` and `Response` objects, so the route can forward requests directly to Aura Auth handlers. + +```ts title="app/api/auth/[...aura]/route.ts" +import { handlers } from "@/lib/auth" + +export const { GET, POST, PATCH } = handlers +``` + +This route handles all requests under `/api/auth/*`. + + + + + +## Usage + +### Server Side Rendering (SSR) + +The `api` object is designed for server environments such as Server Components and Server Actions. + +When you need the active session on the server, pass the current request headers using `headers()` from `next/headers`. That gives Aura Auth access to the cookies and headers required to identify the session. + +#### Sign-In + +```tsx title="app/login/page.tsx" lineNumbers +import { api } from "@/lib/auth" +import { redirect } from "next/navigation" + +export default function LoginPage() { + const signInAction = async () => { + "use server" + const signIn = await api.signIn("github", { + redirect: false, + redirectTo: "/dashboard", + }) + redirect(signIn.signInURL) + } + + return ( +
+ +
+ ) +} +``` + +Use this pattern when you want the server action to own the redirect destination while Aura Auth handles the provider flow. + +#### Get Session + +```tsx title="app/dashboard/page.tsx" lineNumbers +import { api } from "@/lib/auth" +import { headers } from "next/headers" +import { redirect } from "next/navigation" + +export default async function DashboardPage() { + const headersStore = await headers() + + const { session, authenticated } = await api.getSession({ headers: headersStore }) + if (!authenticated) { + redirect("/login") + } + + return ( +
+

Welcome back, {session.user?.name}

+ Profile Avatar +
+ ) +} +``` + +This is the recommended pattern for protected App Router pages: check the session before rendering any private UI. + +#### Sign Out + +```tsx title="app/dashboard/page.tsx" lineNumbers +import { api } from "@/lib/auth" +import { headers } from "next/headers" +import { redirect } from "next/navigation" + +export default async function DashboardPage() { + const signOutAction = async () => { + "use server" + const headerStore = await headers() + const response = await api.signOut({ + headers: headerStore, + }) + if (response.ok) { + redirect("/home") + } + } + return ( +
+ +
+ ) +} +``` + +If you prefer a client-only interaction, you can call `authClient.signOut()` from a client component instead. + +### Client Side Rendering (CSR) + +#### Sign In + +```tsx title="app/components/sign-in-button.tsx" lineNumbers +"use client" +import { authClient } from "@/lib/auth-client" + +export const SignInButton = () => { + const handleSignIn = async () => { + await authClient.signIn("github", { + redirectTo: "/dashboard", + }) + } + + return +} +``` + +Use a client component when you need a clickable auth button, custom modal, or other interactive sign-in entry point. + +#### Get Session + +```tsx title="app/components/user-profile.tsx" lineNumbers +"use client" +import { useEffect, useState } from "react" +import { authClient } from "@/lib/auth-client" + +export const UserProfile = () => { + const [session, setSession] = useState(null) + useEffect(() => { + const fetchSession = async () => { + const { session } = await authClient.getSession() + setSession(session) + } + fetchSession() + }, []) + if (!session) return
Loading...
+ + return ( +
+

Welcome back, {session.user?.name}

+ Profile Avatar +
+ ) +} +``` + +This is useful for session-aware UI that updates after hydration or after a client-side navigation. + +#### Sign Out + +To easily check sessions or log out from client components, use `createAuthClient`. + +```tsx title="app/components/sign-out-button.tsx" lineNumbers +"use client" +import { authClient } from "@/lib/auth-client" + +export const SignOutButton = () => { + const handleSignOut = async () => { + await authClient.signOut({ + redirectTo: "/login", + }) + } + + return +} +``` + +Client-side sign-out is a better fit for navigation menus, profile popovers, and other interactive UI. + +
+ +
+ +--- + +## Common Pitfalls + +- **Mismatched Paths**: Ensure the `basePath` in your auth configuration matches the path where your route handlers are mounted. For example, if your handlers are in `app/api/auth/[...aura]/route.ts`, then `basePath` should be `/api/auth`. +- **Incorrect Headers**: When calling `api.getSession` or `api.signOut` from server components or actions, always pass the current request headers using Next.js's `headers()` function. This allows Aura Auth to read cookies and manage sessions correctly. +- **Don't update cookies in signOut**: When signing out is called, Aura Auth will return a response with `Set-Cookie` headers and it's required to set the cookies using `cookies` function. + +--- + +## Resources + +- [Next.js App Router Documentation](https://nextjs.org/docs/app) +- [Aura Auth Documentation](/quick-start) +- [Next.js Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/nextjs/app-router) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/next-pages-router.mdx b/docs/src/content/docs/integrations/next-pages-router.mdx new file mode 100644 index 00000000..94004670 --- /dev/null +++ b/docs/src/content/docs/integrations/next-pages-router.mdx @@ -0,0 +1,337 @@ +--- +title: Next.js (Pages Router) +description: Build your first authentication flow with Aura Auth and Next.js Pages Router +--- + +This guide walks you through creating a complete authentication flow using **Aura Auth** with the Next.js Pages Router, API Routes, and Server-Side Rendering. + +## Overview + +Aura Auth and Next.js (Pages Router) both use Node.js HTTP primitives (`IncomingMessage` and `ServerResponse`) under the hood. That means Aura Auth needs a small adapter in Pages API Routes, which is included in the example below. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Next.js Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/nextjs/pages-router) for a fully working example + +Then use this guide to integrate Aura Auth with a Next.js application using best practices. + +--- + +## What You'll Build + +You will create a small Next.js Pages Router setup with: + +- a shared `src/lib/auth.ts` server configuration +- a custom `pages/api/auth/[...aura].ts` adapter that forwards requests to Aura Auth handlers +- an optional `src/lib/auth-client.ts` browser client +- server and client examples for session lookup, sign-in, and sign-out + +--- + + + + + +## Project Structure + +```files +next-app +├── src +│ ├── pages +│ │ └── api +│ │ └── auth +│ │ └── [...aura].ts +│ ├── lib +│ │ ├── auth.ts +│ │ └── auth-client.ts +└── .env.local +``` + + + + + +## Environment Setup + +Create a `.env.local` file at the root of your project to store secrets securely. + +```bash title=".env.local" +# 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" +``` + +Never commit your `.env.local` file to version control. Use a secret manager in production. + + + + + +## Setup Aura Auth + +### HTTP Handlers + +Create an `auth.ts` file in `src/lib/` to configure authentication. This file is the shared source of truth for your server handlers, the client helper, and any server-side session utilities. + +```ts title="lib/auth.ts" +import { createAuth } from "@aura-stack/auth" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", + baseURL: "http://localhost:3000", +}) + +export const { handlers, api } = auth +``` + +`basePath` must match the route mounted in `pages/api/auth/[...aura].ts`. `baseURL` should point to your local development server or deployed application URL. + +### Client API + +To use Aura Auth's client-side features, create an `auth-client.ts` file to initialize the client. This is the browser-facing helper for sign-in buttons, sign-out actions, and session-aware UI. + +```ts title="lib/auth-client.ts" +import { createAuthClient } from "@aura-stack/auth/client" + +export const authClient = createAuthClient({ + basePath: "/api/auth", + baseURL: "http://localhost:3000", +}) +``` + + + The `baseURL` should point to your server's URL, and `basePath` MUST match the path where your auth routes are mounted. + + +When you deploy, keep the same `basePath` but update `baseURL` to your production domain or environment-specific public URL. + +## Mount HTTP Handlers + +Create a catch-all route to handle all authentication endpoints dynamically. Next.js Pages Router uses standard Node.js `IncomingMessage` and `ServerResponse` objects, so the handler below translates them into a standard Web `Request` before calling Aura Auth. + +```ts title="pages/api/auth/[...aura].ts" +import { handlers } from "@/lib/auth" +import type { NextApiRequest, NextApiResponse } from "next" + +const getBaseURL = (request: NextApiRequest) => { + const protocol = request.headers["x-forwarded-proto"] ?? "http" + const host = request.headers["x-forwarded-host"] ?? request.headers.host + return `${protocol}://${host}` +} + +const toWebHeaders = (headers: NextApiRequest["headers"]) => { + const webHeaders = new Headers() + for (const [key, value] of Object.entries(headers)) { + if (Array.isArray(value)) { + webHeaders.set(key, value.join(", ")) + continue + } + if (typeof value === "string") { + webHeaders.set(key, value) + } + } + return webHeaders +} + +const setResponseHeaders = (res: NextApiResponse, headers: Headers) => { + for (const [key, value] of headers.entries()) { + res.setHeader(key, value) + } +} + +export const handler = async (req: NextApiRequest, res: NextApiResponse) => { + const method = req.method ?? "GET" + const handler = handlers[method as keyof typeof handlers] + if (!handler) { + return res.status(405).json({ error: `Method ${method} Not Allowed` }) + } + const url = new URL(req.url!, getBaseURL(req)) + const webRequest = new Request(url, { + method, + headers: toWebHeaders(req.headers), + body: method !== "GET" && method !== "HEAD" && req.body ? JSON.stringify(req.body) : undefined, + }) + + try { + const response = await handler(webRequest) + setResponseHeaders(res, response.headers) + + if (response.status >= 300 && response.status < 400) { + const location = response.headers.get("location") + if (location) { + return res.redirect(response.status, location) + } + } + + const contentType = response.headers.get("content-type") ?? "" + if (contentType.includes("application/json")) { + const data = await response.json() + return res.status(response.status).json(data) + } + + const text = await response.text() + return res.status(response.status).send(text) + } catch { + return res.status(500).json({ error: "Internal Server Error" }) + } +} + +export default handler +``` + +This route should be the only file under `/api/auth/*`. It can handle all auth methods, including sign-in, sign-out, callback, and session checks. + + + + + +## Usage + +### Server Side Rendering (SSR) + +Use server-side rendering when you want to protect a page before any UI is sent to the browser. This is the safest pattern for dashboard pages, account settings, and other private routes. + +#### Get Session + +```tsx title="pages/dashboard.tsx" lineNumbers +import { api } from "@/lib/auth" +import type { Session } from "@aura-stack/auth" +import type { GetServerSideProps, InferGetServerSidePropsType } from "next" + +export const getServerSideProps: GetServerSideProps<{ session: Session | null }> = async ({ req }) => { + const session = await api.getSession({ + headers: req.headers as Record, + }) + + return { + props: { + session: session.authenticated ? session.session : null, + }, + } +} + +export default function DashboardPage({ session }: InferGetServerSidePropsType) { + if (!session) { + return

You must be signed in to view this page.

+ } + return ( +
+

Welcome, {session.user?.name}!

+

Email: {session.user?.email}

+
+ ) +} +``` + +The server-side session lookup is the right place to redirect unauthenticated users or render a fallback state. + +
+ + + +### Client Side Rendering (CSR) + +Use client-side rendering when you need interactive auth controls inside menus, modals, or components that cannot use `getServerSideProps`. + +#### Sign In + +```tsx title="pages/login.tsx" lineNumbers +import { authClient } from "@/lib/auth-client" + +export default function LoginPage() { + const signIn = async () => { + const response = await authClient.signIn("github", { + redirect: true, + redirectTo: "/dashboard", + }) + if (!response.ok) { + console.error("Sign-in failed:", response.error) + } + } + + return ( +
+

Login

+ +
+ ) +} +``` + +If you do not want an automatic redirect, set `redirect: false` and handle the returned URL yourself. + +#### Get Session + +```tsx title="components/user-profile.tsx" lineNumbers +import { useEffect, useState } from "react" +import { authClient } from "@/lib/auth-client" + +export const UserProfile = () => { + const [session, setSession] = useState(null) + + useEffect(() => { + const fetchSession = async () => { + const { session } = await authClient.getSession() + setSession(session) + } + fetchSession() + }, []) + + if (!session) return

Loading...

+ + return ( +
+

Welcome back, {session.user?.name}

+

Email: {session.user?.email}

+
+ ) +} +``` + +This pattern works well for menus, avatars, and client-only widgets that need to show the current user after hydration. + +#### Sign Out + +```tsx title="components/sign-out-button.tsx" lineNumbers +import { authClient } from "@/lib/auth-client" + +export const SignOutButton = () => { + const handleSignOut = async () => { + await authClient.signOut({ + redirect: true, + redirectTo: "/", + }) + } + + return +} +``` + +Client-side sign-out is best when the logout control lives inside a dropdown, toolbar, or any interactive client component. + +
+ +
+ +--- + +## Common Pitfalls + +- **Keep `basePath` and the route file aligned**. If your route is `pages/api/auth/[...aura].ts`, the auth configuration should use `basePath: "/api/auth"`. +- **Pass the current request headers on the server**. `api.getSession()` needs the active request headers so Aura Auth can read cookies correctly. +- **Treat `auth.ts` as shared server code**. Put the auth instance in `src/lib/auth.ts` so both API routes and server-side code can reuse it. +- **Use client components only for interaction**. Page protection is stronger when it happens on the server before rendering private UI. + +--- + +## Resources + +- [Next.js Pages Router Documentation](https://nextjs.org/docs/pages) +- [Aura Auth Documentation](/quick-start) +- [Next.js Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/nextjs/pages-router) +- [Integration Guide](/docs/guides/integration) +- [Configuration Reference](/docs/configuration/options) +- [TypeScript Guide](/docs/configuration/typescript) diff --git a/docs/src/content/docs/integrations/next.mdx b/docs/src/content/docs/integrations/next.mdx deleted file mode 100644 index 06d64574..00000000 --- a/docs/src/content/docs/integrations/next.mdx +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: Next.js -description: Build your first authentication flow with Aura Auth and Next.js ---- - -This guide walks you through creating a complete authentication flow using `Aura Auth` in a `Next.js App Router` application, demonstrating the newest DX improvements. - -## Overview - -By the end of this guide, you'll have: - -- OAuth authentication with GitHub -- Unified Next.js Route Handlers -- Elegant Server Actions with `auth.api` -- Client-side data fetching - - - - - -### Install Aura Auth - -If you haven’t installed the package yet: - -```npm -npm install @aura-stack/auth -``` - - - - - -### Configure Environment Variables - -Create a .env file at the root of your project to store secrets securely. - -```bash title=".env.local" -# 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" - -# OAuth Provider Credentials -AURA_AUTH_GITHUB_CLIENT_ID=your_github_client_id -AURA_AUTH_GITHUB_CLIENT_SECRET=your_github_client_secret -``` - -Never commit your `.env` file to version control. Use a secret manager in production. - - - - - -### Create an Auth Configuration - -Create an `auth.ts` file in your root folder (or `src/auth.ts`) to configure authentication. - -```ts title="auth.ts" -import { createAuth } from "@aura-stack/auth" - -export const auth = createAuth({ - oauth: ["github"], - secret: process.env.AURA_AUTH_SECRET!, -}) - -// Unpack the handler and programmatic APIs -export const { handlers, api } = auth -``` - - - - - -### Integrate Route Handlers - -Create a catch-all route to handle all authentication endpoints dynamically. Next.js App Router uses standard Web `Request`/`Response`. - -```ts title="app/api/auth/[...auth]/route.ts" -import { handlers } from "@/auth" - -// Utilize the generic ALL handler to simplify code drastically -export const { ALL: GET, ALL: POST } = handlers -``` - - - - - -### Sign-In and Server Actions - -Next.js Server Actions are a great way to handle mutations programmatically using `auth.api`. Setup a simple sign-in page. - -```tsx title="app/login/page.tsx" lineNumbers -import { api } from "@/auth" -import { redirect } from "next/navigation" - -export default function LoginPage() { - const triggerSignIn = async () => { - "use server" - // Initiates the GitHub redirect via server logic - const response = await api.signIn("github", { - redirectTo: "http://localhost:3000/dashboard", - }) - - // Convert Response to Next.js redirect - redirect(response.headers.get("Location") ?? "/") - } - - return ( -
- -
- ) -} -``` - -
- - - -### Reading Session Data Server-Side - -Instead of making cumbersome internal `fetch` API requests to `/api/auth/session`, Aura Auth simplifies this via `api.getSession`. Read headers seamlessly inside Server Components. - -```tsx title="app/dashboard/page.tsx" lineNumbers -import { api } from "@/auth" -import { headers } from "next/headers" -import { redirect } from "next/navigation" - -export default async function DashboardPage() { - // Pass the Next.js header stream into the programmatic API! - const requestHeaders = await headers() - - // Pass headers directly to the API - const { session } = await api.getSession({ headers: requestHeaders }) - - if (!session) { - redirect("/login") - } - - return ( -
-

Welcome back, {session.user?.name}

- Profile Avatar -
- ) -} -``` - -
- - - -### Client-Side Integration - -To easily check sessions or log out from client components, use `createAuthClient`! - -```tsx title="app/components/LogOutBtn.tsx" lineNumbers -"use client" - -import { createAuthClient } from "@aura-stack/auth/client" -import { useRouter } from "next/navigation" - -const client = createAuthClient({ - baseURL: "http://localhost:3000", - basePath: "/api/auth", -}) - -export default function LogOutBtn() { - const router = useRouter() - - const handleLogout = async () => { - await client.signOut() - router.push("/login") - } - - return -} -``` - - - -
- ---- - -## Available Routes - -Aura Auth automatically sets up these routes via the Route Handler: - -| Route | Method | Description | -| ------------------------- | ---------- | ---------------------------------------------------- | -| `/api/auth/signIn/:oauth` | GET | Initiates the OAuth sign-in flow | -| `/api/auth/session` | GET / POST | Returns / updates the current user session | -| `/api/auth/csrfToken` | GET | Get the CSRF Token to be used in `/api/auth/signOut` | -| `/api/auth/signOut` | POST | Sign out the current session | diff --git a/docs/src/content/docs/integrations/nuxt.mdx b/docs/src/content/docs/integrations/nuxt.mdx index 9f3f120d..320c85da 100644 --- a/docs/src/content/docs/integrations/nuxt.mdx +++ b/docs/src/content/docs/integrations/nuxt.mdx @@ -1,116 +1,152 @@ --- -title: Nuxt.js +title: Nuxt description: Build your first authentication flow with Aura Auth and Nuxt (Nitro) --- -This guide walks you through creating a complete authentication flow using **Aura Auth** in a **Nuxt.js** application. +This guide walks you through creating a complete authentication flow using **Aura Auth** in a Nuxt application. ## Overview -Nuxt runs on the Nitro server engine, which natively uses the `h3` event handler. Aura Auth is highly compatible because you can map standard Web Requests via Nitro's `toWebRequest` utility or directly mount Aura handles. +Nuxt runs on the Nitro server engine, which natively uses `h3` event handlers. Aura Auth integrates cleanly because you can map standard Web Requests via Nitro's `toWebRequest` utility and route them to Aura Auth handlers. + +Before continuing, complete the installation and initial setup: + +- [Quick Start Guide](/docs/quick-start) to create your Aura Auth instance +- [TypeScript Configuration](/docs/configuration/typescript) for TypeScript-specific setup +- [Nuxt Integration App](https://github.com/aura-stack-ts/auth/tree/master/apps/nuxt) for a fully working example + +Then use this guide to integrate Aura Auth with a Nuxt server using best practices. + +--- + +## What You'll Build + +You will create a small Nuxt setup with: + +- a shared `shared/auth.ts` server configuration +- a Nitro route at `server/api/auth/[...aura].ts` that forwards requests to Aura Auth handlers +- a shared browser client in `shared/auth-client.ts` +- a Vue example that signs users in, reads the current session, and signs users out + +--- -### Install Aura Auth +## Project Structure + +```files +nuxt-app +├── server +│ └── api +│ └── auth +│ └── [...aura].ts +├── shared +│ ├── auth.ts +│ └── auth-client.ts +└── .env +``` -Install the package in your Nuxt project: + + + + +## Environment Setup + +Create a `.env` file at the root of your project to store secrets securely. -```npm -npm install @aura-stack/auth +```bash title=".env" +# 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" ``` +Never commit your `.env` file to version control. Use a secret manager in production. + -### Create an Auth Configuration +## Setup Aura Auth + +### HTTP Handlers -Create an `auth.ts` inside your `server/utils` or `server` directory so it is automatically imported or easily accessed by Nitro endpoints. +Create an `auth.ts` file in your `shared` directory so it can be reused by both Nitro endpoints and client utilities. -```ts title="server/utils/auth.ts" +```ts title="shared/auth.ts" import { createAuth } from "@aura-stack/auth" export const auth = createAuth({ oauth: ["github"], - secret: process.env.AURA_AUTH_SECRET!, + basePath: "/api/auth", + baseURL: "http://localhost:3000", }) -``` - - - +export const { handlers, jose, api } = auth +``` -### Integrate with Nitro (server/routes) +`basePath` must match the route mounted in `server/api/auth/[...aura].ts`. `baseURL` should point to your local development server or deployed application URL. -Create a wildcard catch-all route that delegates to Aura's `ALL` handler. Nitro provides `toWebRequest` to ensure `auth.handlers.ALL` receives a standard `Request` object. +### Client API -```ts title="server/routes/auth/[...path].ts" lineNumbers -export default defineEventHandler((event) => { - // Convert the H3 event to a Web Request - const request = toWebRequest(event) +```ts title="shared/auth-client.ts" +import { createAuthClient } from "@aura-stack/auth/client" - // Pass it to Aura Auth - return auth.handlers.ALL(request) +export const authClient = createAuthClient({ + basePath: "/api/auth", + baseURL: "http://localhost:3000", }) ``` -Aura Auth endpoints will now be served at `/auth/...` + + The `baseURL` should point to your server's URL, and `basePath` MUST match the path where your auth routes are mounted. + -### Accessing the Session in Nuxt +## Mount HTTP Handlers + +Create a wildcard catch-all route that delegates to Aura Auth's `ALL` handler. Nitro's `toWebRequest` utility ensures `handlers.ALL` receives a standard `Request` object. -You can protect your API endpoints by reading the session from the incoming event. +```ts title="server/api/auth/[...aura].ts" lineNumbers +import { toWebRequest } from "h3" +import { handlers } from "~/shared/auth" -```ts title="server/api/protected.ts" lineNumbers export default defineEventHandler(async (event) => { - const request = toWebRequest(event) - const session = await auth.api.getSession(request) - - if (!session) { - throw createError({ - statusCode: 401, - statusMessage: "Unauthorized", - }) - } - - return { - message: "You are viewing secure data", - user: session.user, - } + const webRequest = toWebRequest(event) + return await handlers.ALL(webRequest) }) ``` +Aura Auth endpoints will now be served at `/api/auth/*`. + -### Setting up the Client UI +## Usage + +### Client Side Rendering (CSR) With Nuxt, you can use the built-in `createAuthClient` utility to handle authentication directly from your Vue components. ```vue title="app.vue" lineNumbers