Skip to content

fix(auth-guard): keep anonymous routes working when getSession fails (e.g. DB down) - #160

Open
ropdias wants to merge 2 commits into
ThallesP:masterfrom
ropdias:fix/allow-anonymous-db-failure
Open

fix(auth-guard): keep anonymous routes working when getSession fails (e.g. DB down)#160
ropdias wants to merge 2 commits into
ThallesP:masterfrom
ropdias:fix/allow-anonymous-db-failure

Conversation

@ropdias

@ropdias ropdias commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Description

Closes #159.

Problem

AuthGuard.canActivate calls getSession() before it reads the route metadata (@AllowAnonymous() / @OptionalAuth()). Because Better Auth's getSession() goes through the same database adapter, an infrastructure failure (e.g. an unreachable database) makes it reject. With no try/catch around it, that rejection bubbles up and NestJS turns it into a generic 500 on every route — including @AllowAnonymous() liveness/readiness probes, whose entire job is to keep responding while the database is down. The isPublic short-circuit is never reached.

Approach

Wrap the getSession() call in a try/catch and evaluate the route metadata afterwards:

  • On failure, fall back to a null session and log it — mirroring the try/catch + console.error pattern already used by the role/permission checks in this same guard.
  • @AllowAnonymous() routes return true regardless of the failure. The session is still hydrated when the DB is up, so @Session() on public routes keeps working.
  • @OptionalAuth() routes proceed as anonymous.
  • Routes that require a session re-throw the original error, so a real DB outage surfaces as a 5xx instead of a misleading 401 (which would push clients into a logout / redirect-to-login loop they can't escape while the DB is down). Protected-route behavior is otherwise unchanged.

No public API changes — the only observable difference is that anonymous/optional routes no longer 500 when the session lookup fails. It's a patch.

Why not the alternatives raised in the issue thread

  • Reading isPublic first and skipping getSession() entirely would break session hydration on public/optional routes: an authenticated user hitting a public route would lose req.user / req.session (the @Session() / optional-auth pattern).
  • A new injectSessionInPublicRoutes option adds configuration surface for a false dichotomy — the try/catch already gives both behaviors (session hydrated when the DB is up, route still served when it's down) without a new flag to document, test and misconfigure.

Tests

Added tests/e2e/auth-guard-db-failure.e2e.test.ts (runs on both Express and Fastify), simulating a rejecting getSession():

  • @AllowAnonymous()200
  • @OptionalAuth()200 (anonymous)
  • protected → 500 (error surfaced, not masked)

@ThallesP would appreciate your review on this one 🙏

Checklist

  • Addresses a real, reproducible problem (issue linked for non-trivial changes)
  • Used the project toolchain — Bun (not npm/yarn/pnpm)
  • bun run check passes (lint + format)
  • bun run test passes (Express + Fastify)
  • I understand & can maintain every line — including any AI-assisted parts

getSession() was called before the route metadata was evaluated, so an
infrastructure failure (e.g. an unreachable database) rejected and
bubbled up as a 500 on every route — including @AllowAnonymous()
liveness/readiness probes whose whole purpose is to keep responding
while the database is down.

Wrap the getSession() call in a try/catch and evaluate the metadata
afterwards: on failure fall back to a null session and log it (mirroring
the try/catch + console.error pattern already used by the role and
permission checks in this guard). @AllowAnonymous() and @OptionalAuth()
routes then proceed, while routes that require a session re-throw the
original error instead of masking a DB outage as a 401.

Closes ThallesP#159

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pkg-pr-new

pkg-pr-new Bot commented Jul 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/ThallesP/nestjs-better-auth/@thallesp/nestjs-better-auth@160

commit: df14a67

… route

The db-failure regression test asserted only authenticated: false, which
covers req.user. Also assert session: null so the test fully pins the
anonymous state the fix guarantees — otherwise a stray req.session leaking
through would still pass. Mirrors the authenticated-with-auth test, which
already asserts the session shape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

BUG - handlers with AllowAnonymous decorator still use better-auth getSession and hit DB connection

1 participant