Skip to content

Working on issue #26 - #34

Merged
Basharkhan7776 merged 5 commits into
Openlabsops:mainfrom
silky-x0:working-on-issue-#26
Jun 18, 2026
Merged

Basharkhan7776 merged 5 commits into
Openlabsops:mainfrom
silky-x0:working-on-issue-#26

Conversation

@silky-x0

@silky-x0 silky-x0 commented Jun 18, 2026 •

Copy link
Copy Markdown
Collaborator

feat(api): add better-auth with modular architecture

Closes #26


Summary

Installs better-auth and refactors apps/api into a modular, layered architecture with session-based email/password authentication.


Changes

Architecture Refactor

  • Split monolithic src/index.ts into index.ts (server bootstrap) and app.ts (Express factory + middleware wiring)
  • Added barrel router at src/routes/index.ts — app.ts no longer imports individual routes

New Files

File Purpose
src/lib/env.ts Centralized config object from process.env
src/lib/auth.ts betterAuth() instance with Prisma adapter + email/password
src/lib/db.ts Re-exports prisma singleton from @repo/db
src/middleware/error-handler.ts Extracted Express error handler
src/middleware/require-auth.ts Session guard via auth.api.getSession()
src/routes/user/auth.routes.ts POST /register, /login, /logout
src/routes/admin/auth.routes.ts Empty stub for future admin auth
src/controllers/user.controller.ts registerUser, loginUser, logoutUser handlers
.env.example Documents all required environment variables

Auth Endpoints

POST /api/v1/auth/manual/register   → create account
POST /api/v1/auth/manual/login      → sign in (sets session cookie)
POST /api/v1/auth/manual/logout     → end session

Notes

  • Uses existing Prisma schema — no migrations needed (User, Session, Account, Verification models already in place)
  • Sessions stored in DB via better-auth's Prisma adapter (no Redis required)
  • Email verification deferred to a future phase

Testing

# Register
curl -X POST http://localhost:3000/api/v1/auth/manual/register \
  -H "Content-Type: application/json" \
  -d '{"email":"test@test.com","password":"password123","name":"Test"}'

# Login
curl -X POST http://localhost:3000/api/v1/auth/manual/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@test.com","password":"password123"}'

# Logout (pass session cookie from login response)
curl -X POST http://localhost:3000/api/v1/auth/manual/logout \
  -H "Cookie: better-auth.session_token=<token>"

Release Notes

  • Authentication Framework Installed: better-auth package (v1.6.19) added to enable session-based email/password authentication for the API.

  • Three Core Auth Endpoints Implemented:

    • POST /api/v1/auth/manual/register - User registration
    • POST /api/v1/auth/manual/login - Session-based sign-in with cookie support
    • POST /api/v1/auth/manual/logout - Session termination
  • Modular Architecture Established: Organized code into lib/ (configuration, database, auth clients), middleware/ (error handling, auth guards), routes/ (endpoint definitions), and controllers/ (request handlers) for better maintainability and code reuse.

  • Database Session Storage: Sessions persist to PostgreSQL via Prisma adapter—no external Redis dependency required.

  • Environment Configuration: .env.example documents required variables; configuration can be extended to support worker processes using the same auth/database setup.

  • Error Handling: Global error handler middleware in place to catch and respond to server errors uniformly.

  • Authentication Guard: requireAuth middleware available to protect future routes requiring authenticated sessions.

  • Future Considerations:

    • Email verification deferred to future implementation phase
    • Admin auth routes stubbed and ready for implementation
    • Worker process integration ready to consume shared auth/database clients via lib/ modules

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@silky-x0, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 18 seconds. Learn how PR review limits work.

To continue reviewing without waiting, enable usage-based billing in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3505b84e-e5e1-4898-b68c-fc816602640b

📥 Commits

Reviewing files that changed from the base of the PR and between cf7491e and aaeea1b.

📒 Files selected for processing (3)
  • apps/api/src/controllers/user.controller.ts
  • apps/api/src/middleware/require-auth.ts
  • apps/api/src/utils/async-handler.ts
📝 Walkthrough

Walkthrough

Implements better-auth email/password authentication in the Express API. Adds a lib layer (env.ts, db.ts, auth.ts), refactors the Express bootstrap into app.ts and index.ts (with graceful shutdown), introduces errorHandler and requireAuth middleware, adds three user auth controller handlers that proxy to better-auth, and wires them into a versioned route tree.

Changes

better-auth Integration

Layer / File(s) Summary
Env config, DB wrapper, and betterAuth instance
apps/api/src/lib/env.ts, apps/api/src/lib/db.ts, apps/api/src/lib/auth.ts, apps/api/package.json, apps/api/.env.example, .gitignore
config reads env vars with fallbacks; db.ts re-exports the Prisma client from @repo/db; auth.ts instantiates betterAuth with the Prisma adapter, config.auth.secret, and emailAndPassword enabled; better-auth@^1.6.19 is added as a dependency; example env values and a .agent gitignore entry are added.
Express app bootstrap and middleware
apps/api/src/app.ts, apps/api/src/middleware/error-handler.ts, apps/api/src/middleware/require-auth.ts, apps/api/src/index.ts
app.ts wires CORS → JSON → router → errorHandler; errorHandler returns a fixed 500 JSON response; requireAuth calls auth.api.getSession and returns 401 or populates res.locals; index.ts is refactored to import the shared app and config, listen on config.port, and add SIGTERM/SIGINT graceful shutdown.
User auth controllers and route tree
apps/api/src/controllers/user.controller.ts, apps/api/src/routes/user/auth.routes.ts, apps/api/src/routes/admin/auth.routes.ts, apps/api/src/routes/index.ts
registerUser, loginUser, and logoutUser forward headers via fromNodeHeaders to auth.api methods with asResponse: true, copy response headers, and return the auth body; these are mounted at POST /register, /login, /logout under the user auth router; a placeholder admin auth router is created; the route index mounts both under /api/v1/auth/manual and /api/v1/admin/auth.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Express as Express (app.ts)
  participant userController as user.controller.ts
  participant betterAuth as auth.api (better-auth)
  participant Prisma as Prisma / PostgreSQL

  Client->>Express: POST /api/v1/auth/manual/register
  Express->>userController: registerUser(req, res)
  userController->>betterAuth: signUpEmail({ email, password, name, headers, asResponse: true })
  betterAuth->>Prisma: create user record
  Prisma-->>betterAuth: user row
  betterAuth-->>userController: Response (Set-Cookie + body)
  userController->>Client: copy headers + res.status(N).json(data)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Openlabsops/Snap-form#24: Introduces the @repo/db Prisma client export that apps/api/src/lib/db.ts directly re-exports in this PR.
  • Openlabsops/Snap-form#27: Also refactors apps/api/src/index.ts to wire Express middleware and server bootstrap behavior, overlapping directly with this PR's index.ts changes.

Poem

🐇 Hop hop, a new auth gate!
Email and password, never late,
betterAuth with Prisma wired in tight,
Sessions and cookies set just right,
The rabbit signs in — what a delight! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Working on issue #26' is generic and vague, referring only to an issue number without describing the actual changes or purpose. Replace with a descriptive title such as 'Add session-based email/password authentication with better-auth' to clearly convey the main changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR fulfills all primary coding requirements from issue #26: implements session-based email/password auth routes at /api/v1/auth/manual, establishes the specified modular architecture (lib/, middleware/, routes/, controllers/), configures better-auth with Prisma adapter, and separates app setup from server bootstrap.
Out of Scope Changes check ✅ Passed All changes directly support the linked issue #26 requirements: authentication setup, modular architecture refactoring, configuration files, and middleware. The .gitignore update is a minor supporting change that is in-scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/app.ts`:
- Around line 11-13: Import the `express-async-errors` package at the top of the
app.ts file before any other imports. This package patches Express to
automatically catch errors from async route handlers like registerUser,
loginUser, and logoutUser, ensuring that any unhandled rejections are properly
caught and passed to the errorHandler middleware instead of becoming unhandled
rejections.

In `@apps/api/src/controllers/user.controller.ts`:
- Around line 17-19: The current implementation using response.headers.forEach()
with res.setHeader() incorrectly collapses multiple Set-Cookie headers into a
single comma-separated string, corrupting cookie values. Instead of the generic
forEach loop that handles all headers the same way, use
response.headers.getSetCookie() to extract Set-Cookie headers as an array and
set them individually using res.setHeader() for each cookie. Apply this fix to
all three locations in the file where this pattern appears (the forEach +
setHeader blocks around lines 17-19, 35-37, and 49-51).
- Around line 5-55: The async handlers registerUser, loginUser, and logoutUser
are missing error handling for the auth.api method calls, which can throw
exceptions. Wrap the entire body of each of these three functions in a try/catch
block. In the catch block, invoke next(error) to pass the caught error to
Express's error middleware, ensuring exceptions from auth.api calls are properly
handled by the error middleware instead of causing the request to hang or crash.

In `@apps/api/src/lib/env.ts`:
- Around line 1-8: The config object in env.ts uses insecure dummy fallback
values for critical environment variables like DATABASE_URL, BETTER_AUTH_SECRET,
and BETTER_AUTH_URL. Remove the fallback dummy values and instead throw an error
during initialization if these required environment variables are not set. This
ensures the application fails fast at boot time rather than starting with
insecure or invalid configuration. For each critical variable (DATABASE_URL,
BETTER_AUTH_SECRET, BETTER_AUTH_URL), add validation logic that checks if the
environment variable exists and throws an informative error if it is missing.

In `@apps/api/src/middleware/require-auth.ts`:
- Around line 6-24: The `requireAuth` middleware function is async and calls
`auth.api.getSession()` which can throw errors, but these errors are not caught.
Since Express 4.19.2 does not automatically catch errors in async middleware,
unhandled rejections will bypass the error handler. Wrap the body of the
`requireAuth` function (the call to getSession and subsequent logic) in a
try/catch block, and in the catch block, pass the caught error to the `next()`
function so Express's error handler middleware can process it properly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4b45a564-d379-4c3c-89d9-3ae76f9a93ec

📥 Commits

Reviewing files that changed from the base of the PR and between da31f4e and cf7491e.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • .gitignore
  • apps/api/.env.example
  • apps/api/package.json
  • apps/api/src/app.ts
  • apps/api/src/controllers/user.controller.ts
  • apps/api/src/index.ts
  • apps/api/src/lib/auth.ts
  • apps/api/src/lib/db.ts
  • apps/api/src/lib/env.ts
  • apps/api/src/middleware/error-handler.ts
  • apps/api/src/middleware/require-auth.ts
  • apps/api/src/routes/admin/auth.routes.ts
  • apps/api/src/routes/index.ts
  • apps/api/src/routes/user/auth.routes.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-06-16T07:39:18.285Z
Learnt from: Basharkhan7776
Repo: Openlabsops/Snap-form PR: 22
File: apps/api/package.json:10-10
Timestamp: 2026-06-16T07:39:18.285Z
Learning: In the Openlabsops/Snap-form monorepo (Bun workspace), internal workspace package dependencies using the `repo/*` scope must use the version specifier `"*"` (not `"workspace:*"`). Apply this consistently when reviewing all `apps/*/package.json` and `packages/*/package.json` files (e.g., `repo/typescript-config`, `repo/eslint-config`, `repo/types`): don’t restrict the check to newly added `repo/*` packages—`"*"` is the repo-wide convention.

Applied to files:

  • apps/api/package.json
🪛 ast-grep (0.43.0)
apps/api/src/app.ts

[warning] 5-5: Express application should use Helmet
Context: express()
Note: Security best practice.

(missing-helmet-typescript)

🪛 dotenv-linter (4.0.0)
apps/api/.env.example

[warning] 2-2: [UnorderedKey] The BETTER_AUTH_SECRET key should go before the DATABASE_URL key

(UnorderedKey)


[warning] 3-3: [UnorderedKey] The BETTER_AUTH_URL key should go before the DATABASE_URL key

(UnorderedKey)


[warning] 5-5: [UnorderedKey] The NODE_ENV key should go before the PORT key

(UnorderedKey)

🔇 Additional comments (10)
apps/api/src/lib/db.ts (1)

1-3: LGTM!

apps/api/src/lib/auth.ts (1)

1-16: LGTM!

.gitignore (1)

39-40: LGTM!

apps/api/src/middleware/error-handler.ts (1)

1-11: LGTM!

apps/api/src/index.ts (1)

1-10: LGTM!

apps/api/package.json (1)

12-12: LGTM!

apps/api/.env.example (1)

1-5: LGTM!

apps/api/src/routes/user/auth.routes.ts (1)

10-14: LGTM!

apps/api/src/routes/admin/auth.routes.ts (1)

1-8: LGTM!

apps/api/src/routes/index.ts (1)

9-17: LGTM!

Comment thread apps/api/src/app.ts
Comment thread apps/api/src/controllers/user.controller.ts Outdated
Comment thread apps/api/src/controllers/user.controller.ts Outdated
Comment thread apps/api/src/lib/env.ts
Comment thread apps/api/src/middleware/require-auth.ts Outdated

@Basharkhan7776 Basharkhan7776 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! merging, we will add alias in future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[build]: install better auth for nodejs and make auth routes

2 participants