Repository navigation
Refactor authentication guards and add response schemas #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # API | ||
| AXIOM_DOMAIN=https://api.axiom.co | ||
| AXIOM_TOKEN= | ||
| BETTER_AUTH_SECRET= | ||
| DATABASE_URL=postgres://postgres:supersecret@localhost:5432/universal-starter?sslmode=require | ||
| DATASET_NAME=universal- | ||
| EMAIL_FROM=noreply@yourapp.com | ||
| EMAIL_FROM_NAME=Your App Name | ||
| EMAIL_PROVIDER=resend | ||
| NODEMAILER_PASS=your_app_password | ||
| NODEMAILER_SERVICE=gmail | ||
| NODEMAILER_USER=your_email@gmail.com | ||
| PLUNK_API_KEY=your_plunk_api_key_here | ||
| REDIS_URL=redis://default:supersecret@localhost:6379 | ||
| RESEND_API_KEY= | ||
| SMTP_HOST=smtp.gmail.com | ||
| SMTP_PASS=your_app_password | ||
| SMTP_PORT=587 | ||
| SMTP_SECURE=false | ||
| SMTP_USER=your_email@gmail.com | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ yarn-error.* | |
|
|
||
| # local env files | ||
| .env*.local | ||
| .env | ||
|
|
||
| # Expo | ||
| .expo/ | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -4,56 +4,56 @@ import { formatErrorResponse } from "../utils/format-response"; | |||
| import { withAuth } from "./auth"; | ||||
|
|
||||
| export const requireAuth = () => | ||||
| new Elysia({ name: "requireAuth" }) | ||||
| .use(withAuth()) | ||||
| .onBeforeHandle({ as: "scoped" }, ({ session, user, set }) => { | ||||
| if (!session || !user) { | ||||
| const { code: status, message } = getStatusCode(401); | ||||
| set.status = status as number; | ||||
| const envelope = formatErrorResponse({ | ||||
| code: message, | ||||
| problem: { | ||||
| status: status as number, | ||||
| title: "User is not authenticated", | ||||
| type: "urn:problem-type:authentication-error", | ||||
| }, | ||||
| }); | ||||
| new Elysia({ name: "requireAuth" }) | ||||
| .use(withAuth()) | ||||
| .onBeforeHandle({ as: "scoped" }, ({ session, user, set }) => { | ||||
| if (!(session && user)) { | ||||
| const { code: status, message } = getStatusCode(401); | ||||
| set.status = "Unauthorized"; | ||||
| const envelope = formatErrorResponse({ | ||||
| code: message, | ||||
| problem: { | ||||
| status: status as number, | ||||
| title: "User is not authenticated", | ||||
| type: "urn:problem-type:authentication-error", | ||||
| }, | ||||
| }); | ||||
|
|
||||
| throw new Response(JSON.stringify(envelope), { | ||||
| status: status as number, | ||||
| headers: { | ||||
| "Content-Type": "application/problem+json", | ||||
| "www-authenticate": 'Bearer realm="api"', | ||||
| }, | ||||
| }); | ||||
| } | ||||
| }); | ||||
| throw new Response(JSON.stringify(envelope), { | ||||
| status: status as number, | ||||
| headers: { | ||||
| "Content-Type": "application/problem+json", | ||||
| "www-authenticate": 'Bearer realm="api"', | ||||
| }, | ||||
| }); | ||||
| } | ||||
| }); | ||||
|
|
||||
| export const requireRole = (roles: string[]) => | ||||
| new Elysia({ name: "requireRole" }) | ||||
| .use(withAuth()) | ||||
| .use(requireAuth()) | ||||
| .onBeforeHandle({ as: "scoped" }, ({ user, set }) => { | ||||
| const { role } = user || {}; | ||||
| const hasRole = role && roles.includes(role); | ||||
| new Elysia({ name: "requireRole" }) | ||||
| .use(withAuth()) | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Calling Severity Level: Minor
Suggested change
Why it matters? ⭐
Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** apps/api/src/plugins/auth-guards.ts
**Line:** 34:34
**Comment:**
*Logic Error: Calling `.use(withAuth())` before `.use(requireAuth())` duplicates `withAuth` decoration because `requireAuth()` already applies `withAuth`, so Elysia will throw a "property already decorated" error when `auth` is registered twice; drop the extra `.use(withAuth())` to avoid the crash.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. |
||||
| .use(requireAuth()) | ||||
| .onBeforeHandle({ as: "scoped" }, ({ user, set }) => { | ||||
| const { role } = user || {}; | ||||
| const hasRole = role && roles.includes(role); | ||||
|
|
||||
| if (!hasRole) { | ||||
| const { code: status, message } = getStatusCode(403); | ||||
| if (!hasRole) { | ||||
| const { code: status, message } = getStatusCode(403); | ||||
|
|
||||
| set.status = status as number; | ||||
| const envelope = formatErrorResponse({ | ||||
| code: message, | ||||
| problem: { | ||||
| status: status as number, | ||||
| title: "User is not authorized", | ||||
| type: "urn:problem-type:authorization-error", | ||||
| }, | ||||
| }); | ||||
| throw new Response(JSON.stringify(envelope), { | ||||
| status: status as number, | ||||
| headers: { | ||||
| "Content-Type": "application/problem+json", | ||||
| }, | ||||
| }); | ||||
| } | ||||
| }); | ||||
| set.status = "Forbidden"; | ||||
| const envelope = formatErrorResponse({ | ||||
| code: message, | ||||
| problem: { | ||||
| status: status as number, | ||||
| title: "User is not authorized", | ||||
| type: "urn:problem-type:authorization-error", | ||||
| }, | ||||
| }); | ||||
| throw new Response(JSON.stringify(envelope), { | ||||
| status: status as number, | ||||
| headers: { | ||||
| "Content-Type": "application/problem+json", | ||||
| }, | ||||
| }); | ||||
| } | ||||
| }); | ||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,11 +1,11 @@ | ||||||||||
| import { auth } from '@src/lib/auth'; | ||||||||||
| import Elysia from 'elysia'; | ||||||||||
| import { auth } from "@src/lib/auth"; | ||||||||||
| import Elysia from "elysia"; | ||||||||||
|
|
||||||||||
| export const withAuth = () => | ||||||||||
| new Elysia({ name: 'withAuth' }) | ||||||||||
| .decorate('auth', auth) | ||||||||||
| new Elysia({ name: "withAuth" }) | ||||||||||
| .decorate("auth", auth) | ||||||||||
| .derive( | ||||||||||
| { as: 'scoped' }, | ||||||||||
| { as: "scoped" }, | ||||||||||
| async function getSession({ request: { headers } }) { | ||||||||||
| const result = await auth.api.getSession({ headers }); | ||||||||||
|
Comment on lines
9
to
10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Severity Level: Minor
Suggested change
Why it matters? ⭐The helper on auth.api actually walks through request.headers/cookies, so feeding it an object that only has headers leaves Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** apps/api/src/plugins/auth.ts
**Line:** 9:10
**Comment:**
*Type Error: `auth.api.getSession` expects to receive the original `request` object so it can read headers/cookies; by only passing `{ headers }` the underlying call now sees `request` as undefined and will throw when it tries to access `request.headers`, preventing authentication from working.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. |
||||||||||
| if (!result) { | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add quotes around the value with spaces.
The value "Your App Name" contains spaces and should be quoted to ensure proper parsing.
Apply this diff:
📝 Committable suggestion
🧰 Tools
🪛 dotenv-linter (4.0.0)
[warning] 8-8: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
🤖 Prompt for AI Agents