diff --git a/apps/elysia/README.md b/apps/elysia/README.md index 354e3365..f11ea6d7 100644 --- a/apps/elysia/README.md +++ b/apps/elysia/README.md @@ -14,6 +14,14 @@ This project demonstrates Aura Auth authentication using [OAuth 2.0 providers](https://aura-stack-auth.vercel.app/docs/) in a [Elysia](https://elysiajs.com/) application. +This integration utilizes the dedicated [`@aura-stack/elysia`](../../packages/elysia) package, which provides standard middlewares and first-class TypeScript support for Elysia applications. + +## Features Demo + +- **Type-safe Middleware**: Uses `withAuth` to protect routes and infer session shapes. +- **Unified Auth Handler**: Reuses framework-agnostic core logic via `toHandler`. +- **Global Context**: Demonstrates how `session` is automatically populated and typed. + ## Getting Started You can run the documentation site locally for development or contribution. diff --git a/apps/elysia/package.json b/apps/elysia/package.json index 6d797740..846adf18 100644 --- a/apps/elysia/package.json +++ b/apps/elysia/package.json @@ -11,7 +11,7 @@ "format:check": "oxfmt --check" }, "dependencies": { - "@aura-stack/auth": "workspace:*", + "@aura-stack/elysia": "workspace:*", "elysia": "^1.4.28" }, "devDependencies": { diff --git a/apps/elysia/src/auth.ts b/apps/elysia/src/auth.ts deleted file mode 100644 index 791e04fd..00000000 --- a/apps/elysia/src/auth.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { type AuthInstance, createAuth } from "@aura-stack/auth" - -export const { handlers, jose, api }: AuthInstance = createAuth({ - oauth: ["github"], - basePath: "/api/auth", - trustedOrigins: ["http://localhost:3000", "https://*.vercel.app"], -}) diff --git a/apps/elysia/src/index.ts b/apps/elysia/src/index.ts index d18bc02a..568a1d43 100644 --- a/apps/elysia/src/index.ts +++ b/apps/elysia/src/index.ts @@ -1,14 +1,13 @@ import { Elysia } from "elysia" -import { toElysiaHandler } from "./lib/handler" -import { withAuthPlugin } from "./plugins/with-auth" +import { toHandler, withAuth } from "@/lib/auth" const app = new Elysia() app.get("/", () => "Welcome to the Aura Auth Elysia App!") -app.all("/api/auth/*", toElysiaHandler) +app.all("/api/auth/*", toHandler) -app.use(withAuthPlugin).get("/api/protected", (ctx) => { +app.derive(withAuth).get("/api/protected", (ctx) => { if (!ctx.session) { return Response.json( { diff --git a/apps/elysia/src/lib/auth.ts b/apps/elysia/src/lib/auth.ts new file mode 100644 index 00000000..7794e5c7 --- /dev/null +++ b/apps/elysia/src/lib/auth.ts @@ -0,0 +1,8 @@ +import { createAuth } from "@aura-stack/elysia" + +export const auth = createAuth({ + oauth: ["github"], + basePath: "/api/auth", +}) + +export const { api, jose, toHandler, withAuth } = auth diff --git a/apps/elysia/src/plugins/with-auth.ts b/apps/elysia/src/plugins/with-auth.ts deleted file mode 100644 index 64184e63..00000000 --- a/apps/elysia/src/plugins/with-auth.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Elysia } from "elysia" -import { api } from "../auth" - -export const withAuthPlugin = new Elysia({ name: "with-auth" }) - .resolve({ as: "scoped" }, async (ctx) => { - try { - const session = await api.getSession({ - headers: ctx.request.headers, - }) - if (!session.authenticated) { - return { session: null } - } - return { session } - } catch { - return { session: null } - } - }) - .get("/api/auth/me", ({ session }) => session) diff --git a/apps/elysia/tsconfig.json b/apps/elysia/tsconfig.json index cc223272..3b1b814d 100644 --- a/apps/elysia/tsconfig.json +++ b/apps/elysia/tsconfig.json @@ -1,5 +1,10 @@ { "extends": "@aura-stack/tsconfig/bun.json", + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + }, "include": ["src"], "exclude": ["dist", "node_modules"] } diff --git a/bun.lock b/bun.lock index 1457285d..2db15f7a 100644 --- a/bun.lock +++ b/bun.lock @@ -70,7 +70,7 @@ "name": "elysia", "version": "0.1.0", "dependencies": { - "@aura-stack/auth": "workspace:*", + "@aura-stack/elysia": "workspace:*", "elysia": "^1.4.28", }, "devDependencies": { @@ -315,6 +315,21 @@ "typescript": "catalog:typescript", }, }, + "packages/elysia": { + "name": "@aura-stack/elysia", + "version": "0.0.0", + "dependencies": { + "@aura-stack/auth": "workspace:*", + }, + "devDependencies": { + "@aura-stack/tsconfig": "workspace:*", + "@aura-stack/tsup-config": "workspace:*", + "elysia": "^1.2.22", + }, + "peerDependencies": { + "elysia": ">=1.0.0", + }, + }, "packages/express": { "name": "@aura-stack/express", "version": "0.0.0", @@ -480,6 +495,8 @@ "@aura-stack/auth": ["@aura-stack/auth@workspace:packages/core"], + "@aura-stack/elysia": ["@aura-stack/elysia@workspace:packages/elysia"], + "@aura-stack/express": ["@aura-stack/express@workspace:packages/express"], "@aura-stack/hono": ["@aura-stack/hono@workspace:packages/hono"], @@ -3652,6 +3669,8 @@ "@astrojs/node/send": ["send@1.2.1", "", { "dependencies": { "debug": "4.4.3", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "fresh": "2.0.0", "http-errors": "2.0.1", "mime-types": "3.0.2", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "1.2.1", "statuses": "2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + "@aura-stack/elysia/elysia": ["elysia@1.4.28", "", { "dependencies": { "cookie": "1.1.1", "fast-decode-uri-component": "1.0.1", "memoirist": "0.4.0" }, "optionalDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" }, "peerDependencies": { "@sinclair/typebox": "0.34.48", "exact-mirror": "0.2.7", "file-type": "21.3.3", "openapi-types": "12.1.3" } }, "sha512-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg=="], + "@aura-stack/express/express": ["express@4.22.1", "", { "dependencies": { "accepts": "1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.4", "content-disposition": "0.5.4", "content-type": "1.0.5", "cookie": "0.7.2", "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "finalhandler": "1.3.2", "fresh": "0.5.2", "http-errors": "2.0.1", "merge-descriptors": "1.0.3", "methods": "1.1.2", "on-finished": "2.4.1", "parseurl": "1.3.3", "path-to-regexp": "1.9.0", "proxy-addr": "2.0.7", "qs": "6.14.2", "range-parser": "1.2.1", "safe-buffer": "5.2.1", "send": "0.19.2", "serve-static": "1.16.3", "setprototypeof": "1.2.0", "statuses": "2.0.2", "type-is": "1.6.18", "utils-merge": "1.0.1", "vary": "1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="], "@aura-stack/hono/hono": ["hono@4.12.8", "", {}, "sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A=="], diff --git a/deno.json b/deno.json index 1bb2b90a..98a86683 100644 --- a/deno.json +++ b/deno.json @@ -1,13 +1,3 @@ { - "workspace": [ - "packages/core", - "packages/jose", - "packages/rate-limiter", - "packages/hono", - "packages/express", - "packages/react", - "apps/oak", - "apps/deno", - "apps/supabase/**" - ] + "workspace": ["packages/**", "apps/oak", "apps/deno", "apps/supabase/**"] } diff --git a/deno.lock b/deno.lock index b980da95..c653e61c 100644 --- a/deno.lock +++ b/deno.lock @@ -18,6 +18,7 @@ "npm:@testing-library/react@^16.3.2": "16.3.2_@testing-library+dom@10.4.1_react@19.2.4_react-dom@19.2.4__react@19.2.4", "npm:@types/supertest@^6.0.3": "6.0.3", "npm:@vitest/coverage-v8@^4.0.14": "4.1.0_vitest@4.1.0__vite@8.0.0", + "npm:elysia@^1.2.22": "1.4.28_@sinclair+typebox@0.34.49_exact-mirror@0.2.7__@sinclair+typebox@0.34.49_file-type@21.3.4_openapi-types@12.1.3", "npm:eslint@^9.35.0": "9.39.4", "npm:hono@4": "4.12.1", "npm:jose@^6.1.2": "6.2.1", @@ -134,6 +135,9 @@ "@bcoe/v8-coverage@1.0.2": { "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==" }, + "@borewit/text-codec@0.2.2": { + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==" + }, "@emnapi/core@1.9.0": { "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", "dependencies": [ @@ -800,6 +804,9 @@ "os": ["win32"], "cpu": ["x64"] }, + "@sinclair/typebox@0.34.49": { + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==" + }, "@standard-schema/spec@1.1.0": { "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==" }, @@ -825,6 +832,16 @@ "react-dom" ] }, + "@tokenizer/inflate@0.4.1": { + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "dependencies": [ + "debug", + "token-types" + ] + }, + "@tokenizer/token@0.3.0": { + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, "@turbo/darwin-64@2.8.18": { "integrity": "sha512-3QNJ8VR2y1+AZX1HRB2uAvBWHWYpyWMYuDPAPHwhmpC74YweQmPh41dQZ9fkNcgT1eZNgYKf6Q3Hq7i0XK3Ybg==", "os": ["darwin"], @@ -1220,6 +1237,18 @@ "gopd" ] }, + "elysia@1.4.28_@sinclair+typebox@0.34.49_exact-mirror@0.2.7__@sinclair+typebox@0.34.49_file-type@21.3.4_openapi-types@12.1.3": { + "integrity": "sha512-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg==", + "dependencies": [ + "@sinclair/typebox", + "cookie", + "exact-mirror", + "fast-decode-uri-component", + "file-type", + "memoirist", + "openapi-types" + ] + }, "es-define-property@1.0.1": { "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" }, @@ -1368,9 +1397,21 @@ "event-target-shim@5.0.1": { "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, + "exact-mirror@0.2.7_@sinclair+typebox@0.34.49": { + "integrity": "sha512-+MeEmDcLA4o/vjK2zujgk+1VTxPR4hdp23qLqkWfStbECtAq9gmsvQa3LW6z/0GXZyHJobrCnmy1cdeE7BjsYg==", + "dependencies": [ + "@sinclair/typebox" + ], + "optionalPeers": [ + "@sinclair/typebox" + ] + }, "expect-type@1.3.0": { "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==" }, + "fast-decode-uri-component@1.0.1": { + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==" + }, "fast-deep-equal@3.1.3": { "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, @@ -1405,6 +1446,15 @@ "flat-cache" ] }, + "file-type@21.3.4": { + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", + "dependencies": [ + "@tokenizer/inflate", + "strtok3", + "token-types", + "uint8array-extras" + ] + }, "find-up@5.0.0": { "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dependencies": [ @@ -1543,6 +1593,9 @@ "ms" ] }, + "ieee754@1.2.1": { + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore@5.3.2": { "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==" }, @@ -1749,6 +1802,9 @@ "math-intrinsics@1.1.0": { "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, + "memoirist@0.4.0": { + "integrity": "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg==" + }, "methods@1.1.2": { "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, @@ -1860,6 +1916,9 @@ ], "bin": true }, + "openapi-types@12.1.3": { + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==" + }, "optionator@0.9.4": { "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dependencies": [ @@ -2169,6 +2228,12 @@ "strip-json-comments@3.1.1": { "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, + "strtok3@10.3.5": { + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "dependencies": [ + "@tokenizer/token" + ] + }, "sucrase@3.35.1": { "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "dependencies": [ @@ -2265,6 +2330,14 @@ "tinyrainbow@3.1.0": { "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==" }, + "token-types@6.1.2": { + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "dependencies": [ + "@borewit/text-codec", + "@tokenizer/token", + "ieee754" + ] + }, "tr46@0.0.3": { "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, @@ -2322,6 +2395,9 @@ "ufo@1.6.3": { "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==" }, + "uint8array-extras@1.5.0": { + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==" + }, "undici-types@5.26.5": { "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, @@ -2477,6 +2553,16 @@ ] } }, + "packages/elysia": { + "dependencies": [ + "npm:elysia@^1.2.22" + ], + "packageJson": { + "dependencies": [ + "npm:elysia@^1.2.22" + ] + } + }, "packages/express": { "packageJson": { "dependencies": [ diff --git a/packages/elysia/CHANGELOG.md b/packages/elysia/CHANGELOG.md new file mode 100644 index 00000000..d5f1da45 --- /dev/null +++ b/packages/elysia/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog - `@aura-stack/elysia` + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- + +## [Unreleased] + +### Added + +- Introduced seamless Elysia integration package that encapsulates the core authentication logic into plugins and handlers for session management and authentication flows. [#140](https://github.com/aura-stack-ts/auth/pull/140) diff --git a/packages/elysia/README.md b/packages/elysia/README.md new file mode 100644 index 00000000..f9b67b4a --- /dev/null +++ b/packages/elysia/README.md @@ -0,0 +1,90 @@ +
+ Made with ❤️ by Aura Stack team +
diff --git a/packages/elysia/deno.json b/packages/elysia/deno.json new file mode 100644 index 00000000..01652a8a --- /dev/null +++ b/packages/elysia/deno.json @@ -0,0 +1,20 @@ +{ + "name": "@aura-stack/elysia", + "version": "0.0.0", + "license": "MIT", + "tasks": { + "dev": "deno run --watch src/index.ts" + }, + "exports": { + ".": "./src/index.ts", + "./oauth": "./src/oauth/index.ts" + }, + "imports": { + "@/": "./src/", + "elysia": "npm:elysia@^1.2.22" + }, + "publish": { + "include": ["src/**/*.ts", "README.md", "CHANGELOG.md"] + }, + "exclude": ["dist", "node_modules"] +} diff --git a/packages/elysia/package.json b/packages/elysia/package.json new file mode 100644 index 00000000..50874c4f --- /dev/null +++ b/packages/elysia/package.json @@ -0,0 +1,66 @@ +{ + "name": "@aura-stack/elysia", + "version": "0.0.0", + "private": false, + "type": "module", + "description": "Elysia adapter for Aura Auth authentication library", + "scripts": { + "dev": "tsup --watch", + "build": "tsup", + "lint": "oxlint", + "lint:fix": "oxlint --fix", + "test": "vitest --run", + "test:watch": "vitest", + "test:coverage": "vitest --run --coverage", + "format": "oxfmt", + "format:check": "oxfmt --check", + "type-check": "tsc --noEmit", + "clean": "rm -rf dist", + "clean:cts": "if [ -d dist ]; then find dist -type f -name \"*.cts\" -delete; fi", + "prepublish": "pnpm clean:cts" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/aura-stack-ts/auth" + }, + "sideEffects": false, + "files": [ + "dist" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./oauth": { + "types": "./dist/oauth/index.d.ts", + "import": "./dist/oauth/index.js", + "require": "./dist/oauth/index.cjs" + } + }, + "keywords": [ + "auth", + "elysia", + "authentication", + "aura-stack" + ], + "author": "Aura Stack