Skip to content

chore(examples): add Express integration app#96

Merged
halvaradop merged 3 commits intomasterfrom
chore/add-express-integration-app
Feb 20, 2026
Merged

chore(examples): add Express integration app#96
halvaradop merged 3 commits intomasterfrom
chore/add-express-integration-app

Conversation

@halvaradop
Copy link
Member

@halvaradop halvaradop commented Feb 19, 2026

Description

This pull request introduces an Express integration example for @aura-stack/auth. The new example demonstrates how to integrate Aura Auth within a backend framework, providing middleware to manage OAuth 2.0 authentication flows, session handling, CSRF protection, and sign-out functionality. The application also mounts additional endpoints such as /health and /api/protected to validate and demonstrate the integration behavior in a server environment.

Note

This is the first backend-focused integration example and the first to include automated testing. Unlike frontend integration, where flows are typically driven by browser interactions, backend environments require explicit request handling and verification, which motivated the inclusion of test coverage for authentication flows.

Resources

Summary by CodeRabbit

  • New Features

    • Added a new Express app with OAuth 2.0 authentication supporting multiple providers, sign-in/redirect flows, session endpoints, CSRF token endpoint, and a protected sample route.
  • Documentation

    • Added README with setup and local development instructions.
  • Tests

    • Added tests covering authentication flows, session handling, CSRF, and protected routes.
  • Chores

    • Added project manifest, TypeScript and test configs, .gitignore, and an environment example template.

@halvaradop halvaradop added the examples Example code, demos, or sample implementations. label Feb 19, 2026
@vercel
Copy link

vercel bot commented Feb 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
auth Skipped Skipped Feb 20, 2026 2:33am
auth-nextjs-demo Skipped Skipped Feb 20, 2026 2:33am

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

This PR adds a complete Express integration for Aura Auth: package/config files, an Express server and entrypoint, auth setup (createAuth handlers & jose), middleware to bridge Web API handlers to Express, session utilities and verification middleware, TypeScript types, tests, README, .env example, and .gitignore.

Changes

Cohort / File(s) Summary
Project config & meta
apps/express/package.json, apps/express/tsconfig.json, apps/express/vitest.config.ts, apps/express/.env.example, apps/express/.gitignore, .vscode/.settings.json
New package manifest, TS config with path aliases, Vitest config (generates test secrets and env vars), environment example with OAuth placeholders, comprehensive .gitignore, and minor VSCode settings change.
Auth core
apps/express/src/auth.ts
Creates Aura Auth instance via createAuth, exposes oauth list, handlers, and jose, configured with /api/auth basePath and trustedOrigins.
Express server & entry
apps/express/src/server.ts, apps/express/src/index.ts
Express app setup, JSON/urlencoded parsers, routes mounting for /api/auth/*, protected GET /api/protected, and startup entry that reads PORT and starts server.
Middleware & adapters
apps/express/src/middlewares/auth.ts
Bridge utilities: convert Express Request -> Web API Request, apply Web API Response -> Express Response (headers, cookies, redirects, bodies), and toExpressHandler middleware wrapper.
Session helpers & guards
apps/express/src/lib/get-session.ts, apps/express/src/lib/verify-session.ts
getSession reads cookies, finds session_token, decodes JWT via jose and returns Session or null; verifySession middleware enforces session presence and attaches it to res.locals.session.
Types & docs
apps/express/src/types.d.ts, apps/express/README.md
Adds Express.Locals augmentation to include optional session?: Session; README with setup and usage notes.
Tests
apps/express/test/index.test.ts
Vitest suite covering signIn redirect, session endpoint (unauth/authenticated via cookie), csrfToken, and protected route behavior using generated JWTs and cookie simulation.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Express as Express Server
    participant AuthBridge as Auth Middleware
    participant Aura as Aura Auth Handler
    participant GitHub as GitHub OAuth
    Client->>Express: GET /api/auth/signIn/github
    Express->>AuthBridge: toExpressHandler
    AuthBridge->>Aura: Invoke Aura Web API handler (Web Request)
    Aura->>GitHub: Redirect to OAuth authorize
    GitHub-->>Aura: OAuth response/redirect
    Aura-->>AuthBridge: Web Response (302 + Set-Cookie)
    AuthBridge-->>Express: Apply response (headers, cookies, Location)
    Express-->>Client: 302 redirect with Location
Loading
sequenceDiagram
    participant Client
    participant Express as Express Server
    participant Verify as verifySession
    participant GetSession as getSession
    participant Jose as jose (decoder)
    participant Protected as Protected Route
    Client->>Express: GET /api/protected (with cookie)
    Express->>Verify: verifySession middleware
    Verify->>GetSession: extract cookie & decode
    GetSession->>Jose: decode JWT
    Jose-->>GetSession: session payload
    GetSession-->>Verify: Session object
    Verify->>Express: attach session to res.locals
    Express->>Protected: handler executes and returns 200 + session
    Protected-->>Client: 200 with user/session data
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped into Express with joy and delight,
Cookies decoded by moonlit night,
Redirects to GitHub, sessions held tight,
Middleware bridges make everything right,
A little rabbit cheers—auth takes flight! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding an Express integration example app to the repository.
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 docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/add-express-integration-app

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (8)
apps/express/src/lib/get-session.ts (1)

14-22: Manual cookie parsing is redundant given cookie-parser middleware.

cookie-parser is a listed runtime dependency and presumably applied via app.use(cookieParser()) in index.ts. When active, req.cookies is already a parsed Record<string, string>, making the manual split/decodeURIComponent pipeline on the raw Cookie header redundant. Using req.cookies is shorter, avoids double-parsing, and handles edge cases (e.g. cookies with = in the value, whitespace variants) consistently with the rest of the app.

♻️ Proposed refactor
 export const getSession = async (request: Request): Promise<Session | null> => {
-    const cookieHeader = request.headers.cookie
-    if (!cookieHeader) return null
     try {
-        const cookies = Object.fromEntries(
-            cookieHeader
-                .split(";")
-                .map((c) => c.trim().split("="))
-                .map(([key, ...val]) => [decodeURIComponent(key), decodeURIComponent(val.join("="))])
-        )
-
-        const sessionCookieKey = Object.keys(cookies).find((k) => k.includes("session_token"))
+        const cookies: Record<string, string> = request.cookies ?? {}
+        const sessionCookieKey = Object.keys(cookies).find((k) => k.includes("session_token"))
         if (!sessionCookieKey) return null

Note: this requires @types/cookie-parser in devDependencies to give TypeScript the req.cookies type on the Express Request.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/src/lib/get-session.ts` around lines 14 - 22, The manual cookie
parsing in getSession (the cookieHeader split/decodeURIComponent block) is
redundant — replace that logic by reading the parsed cookies from
request.cookies (provided by cookie-parser middleware) and use that
Record<string,string> for session lookup; remove the custom split/map pipeline
in the getSession function and rely on req.cookies to avoid double-parsing and
handle edge cases, and ensure `@types/cookie-parser` is added to devDependencies
so TypeScript recognizes request.cookies on the Express Request type.
apps/express/src/auth.ts (1)

4-4: oauth export enumerates all built-in providers, not the configured ones.

Object.keys(builtInOAuthProviders) returns all 10 built-in providers (github, bitbucket, figma, …), but createAuth is configured with only ["github"]. Any consumer iterating this array to render sign-in buttons or derive available providers will see 10 options when only 1 is functional.

Consider either aligning the export with the actual configuration or renaming it to make its scope clear (e.g. availableOAuthProviders).

♻️ Proposed fix
-export const oauth = Object.keys(builtInOAuthProviders) as BuiltInOAuthProvider[]
+/** All built-in OAuth providers supported by Aura Auth (not all are configured in this app). */
+export const allOAuthProviders = Object.keys(builtInOAuthProviders) as BuiltInOAuthProvider[]
+
+/** OAuth providers enabled in this app's createAuth config. */
+export const configuredOAuthProviders: BuiltInOAuthProvider[] = ["github"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/src/auth.ts` at line 4, The exported oauth array is listing
every key from builtInOAuthProviders (export const oauth) rather than the actual
providers configured in createAuth, causing UI to show non-functional options;
update the export to reflect the configured providers (e.g., derive the list
from the createAuth configuration or export a new name like
availableOAuthProviders that is populated from the actual auth config) or rename
the existing export to make its scope explicit (oauthAllProviders) and add a
separate configuredProviders/availableOAuthProviders export that reads the
provider keys used in createAuth so consumers only see functional providers.
apps/express/tsconfig.json (1)

6-6: test/ is excluded from type-checking.

The include array covers only src. The type-check script (tsc --noEmit) will therefore silently skip apps/express/test/. Consider adding "test" to include, or adding a separate tsconfig.test.json that extends this file and adds the test directory, so TypeScript type errors in tests are caught in CI.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/tsconfig.json` at line 6, The tsconfig’s "include" only lists
"src" so the test directory is skipped by the type-check step; update the
"include" array to also include "test" (add "test") or create a new
tsconfig.test.json that extends this tsconfig and adds "test" to its "include",
and ensure the CI/type-check script (the `type-check` step invoking tsc
--noEmit) uses the updated config so types in apps/express/test/ are checked.
apps/express/.gitignore (1)

1-186: Deduplicate entries and remove framework-specific artifacts not relevant to Express.

The file appears to be assembled from multiple gitignore templates without deduplication. Several entries appear 2–3 times (.DS_Store, dist, .env, logs, *.log, .cache, .nuxt, .nitro, .output, node_modules). Additionally, entries specific to TanStack Start / Nuxt scaffolding (count.txt, todos.json, .tanstack, .vinxi, .nitro, .nuxt, .output) are unlikely to be needed for an Express app.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/.gitignore` around lines 1 - 186, The .gitignore contains
duplicate and irrelevant entries merged from multiple templates; remove repeated
entries (e.g., .DS_Store, dist, .env, logs, *.log, .cache, node_modules) so each
pattern appears only once and delete framework-specific artifacts not used by an
Express app (examples: .nuxt, .nitro, .output, .tanstack, .vinxi, count.txt,
todos.json) leaving only Express-relevant ignores (node_modules, logs, coverage,
.env, build/dist outputs, editor caches). Ensure unique entries remain for
patterns like .env, .env.*, !.env.example, node_modules, coverage, .DS_Store,
dist, .cache, logs, and remove the duplicated blocks and unrelated framework
lines.
apps/express/src/middleware/with-auth.ts (1)

14-24: LGTM — middleware logic is correct and well-documented.

The guard pattern (null session → 401, session present → attach to res.locals and next()) is clean. The JSDoc example in the comment matches the implementation.

One optional improvement: augment res.locals with the Session type to get compile-time safety on downstream handlers that read res.locals.session:

// e.g., in a express.d.ts or types.d.ts file in src/
import type { Session } from "@aura-stack/auth"

declare global {
    namespace Express {
        interface Locals {
            session?: Session
        }
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/src/middleware/with-auth.ts` around lines 14 - 24, Add a
TypeScript declaration merging so Express.Res.locals is typed with the Session
shape used in withAuth: create a global declaration file that imports type {
Session } from "@aura-stack/auth" and augments the Express namespace with
interface Locals { session?: Session }, then ensure the declaration file is
included in the TS build so downstream handlers reading res.locals.session get
compile-time safety; reference the withAuth middleware and res.locals.session
when applying this change.
apps/express/vitest.config.ts (1)

10-13: Consider making coverage opt-in rather than always-on.

enabled: true means every invocation of vitest in this workspace runs V8 instrumentation, adding measurable overhead to local dev iterations. The conventional pattern is to enable coverage only via the --coverage CLI flag (or in CI config), leaving enabled either absent or false here.

♻️ Proposed change
         coverage: {
             provider: "v8",
-            enabled: true,
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/vitest.config.ts` around lines 10 - 13, The vitest coverage
block currently has enabled: true which forces V8 instrumentation on every run;
change the coverage config so it is opt-in by removing or setting enabled to
false in the coverage object (the section containing provider: "v8" and enabled)
and rely on the --coverage CLI flag or CI config to enable coverage when needed;
ensure the coverage provider remains set to "v8" if you keep the block but make
enabled opt-in.
apps/express/test/index.test.ts (1)

56-64: No positive-path test for /api/protected — consider adding an authenticated case.

The suite only tests the 401 unauthenticated path. Without an authenticated test, withAuth correctly populating res.locals.session and the handler returning it are never exercised.

💡 Suggested additional test
test("returns 200 with session when a valid session cookie is present", async () => {
    const sessionToken = await jose.encodeJWT({
        sub: "johndoe",
        name: "John Doe",
        email: "johndoe@example.com",
    })
    const response = await supertest(app)
        .get("/api/protected")
        .set("Cookie", [`aura-auth.session_token=${sessionToken}`])
    expect(response.status).toBe(200)
    expect(response.body).toMatchObject({
        message: "You have access to this protected resource.",
        session: expect.objectContaining({ sub: "johndoe" }),
    })
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/test/index.test.ts` around lines 56 - 64, Add a positive-path
test to apps/express/test/index.test.ts that exercises the withAuth middleware
and the GET /api/protected handler: generate a valid token with jose.encodeJWT,
set it on the request as the cookie name aura-auth.session_token, call
supertest(app).get("/api/protected") with .set("Cookie", [...]) and assert
response.status is 200 and response.body includes the expected message plus a
session object containing the subject (e.g., sub: "johndoe"); this ensures
withAuth populates res.locals.session and the handler returns it.
apps/express/src/middleware/auth.ts (1)

74-76: Caught error is silently discarded — add logging before the 500 response.

Without logging, runtime failures in the auth handler are invisible. At minimum, emit the error to stderr.

♻️ Proposed change
     } catch (error) {
+        console.error("[authMiddleware] handler threw:", error)
         return res.status(500).json({ error: "Internal Server Error" })
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/src/middleware/auth.ts` around lines 74 - 76, The catch block
inside the auth middleware that currently does "return res.status(500).json({
error: 'Internal Server Error' })" is discarding the thrown error; modify that
catch to log the error to stderr before returning the 500 (use
console.error(error) or the existing logger if available) so runtime failures in
the auth handler are visible; ensure you reference the same catch block in the
auth middleware (auth.ts) and keep the response behavior unchanged except for
the added logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/express/.env.example`:
- Around line 1-6: Add distinct per-variable comments clarifying that
AURA_AUTH_SALT is an opaque salt/nonce used for key derivation or hashing/pepper
(e.g., for deriving token keys or hashing secrets) and that AURA_AUTH_SECRET is
the actual secret signing key used to sign and verify JWT tokens; keep the
existing example generation hints (openssl rand -base64 32) and leave empty
string defaults in the template to avoid embedding real credentials. Ensure you
name the variables AURA_AUTH_SALT and AURA_AUTH_SECRET in the comments so
contributors know which to set and why.

In `@apps/express/package.json`:
- Line 2: The package "name" in package.json is colliding with the npm express
package; change the "name" field (e.g., to a scoped, unique identifier like
"@aura-stack/express-example") and update any workspace dependency references
that point to "express" so they now reference the new scoped name; ensure the
package.json "name" value is valid per npm rules and then run a workspace
install to verify no workspace:* entry resolves to the real express package.
- Line 11: The package's "test" script runs "vitest run" but vitest is missing
from this package's devDependencies; update apps/express package.json to add
"vitest" under devDependencies so the package is self-contained (ensure the
package name "vitest" is added at an appropriate version and saved into the
devDependencies section adjacent to the existing scripts/devDependencies
entries).

In `@apps/express/README.md`:
- Line 19: Replace the incorrect docs-site phrasing in apps/express/README.md
with a brief description that this repo is the Express integration app (e.g.,
how to run the Express server locally for development), and update the default
local URL from http://localhost:3000 to http://localhost:8080 so it matches the
server startup logic in src/index.ts which uses process.env.PORT ?? 8080.

In `@apps/express/src/auth.ts`:
- Around line 10-15: The logger object currently has level: "debug" and an
unconditional console.log in its log({ message, structuredData, msgId }) method
which will spam production; change the logger to derive its level from an
environment variable (e.g., process.env.LOG_LEVEL or gate by
process.env.NODE_ENV !== "production") and update the log method in the same
logger object so it only calls console.log when the resolved level permits debug
output (or when LOG_LEVEL === "debug"), otherwise no-op or route to a less
verbose output; modify the logger configuration and the log function (the
logger.level value and logger.log method) to use that env check.

In `@apps/express/src/index.ts`:
- Around line 25-28: The module currently calls app.listen(PORT, ...) at import
time, causing tests to open a real TCP socket; remove that unconditional call
from index.ts and either: 1) create a new entrypoint server.ts that imports {
app } from "./index.js", reads PORT (process.env.PORT ?? 8080) and calls
app.listen(...) with the same log lines, then update your start/main config to
point to server.ts, or 2) wrap the existing app.listen(...) in a runtime-only
guard (e.g., only call app.listen when require.main === module or when
process.env.NODE_ENV !== 'test') so tests can import { app } without starting
the server. Ensure symbols referenced are app, PORT and the new server.ts
entrypoint so tests import index.ts but the real listen happens only in
server.ts or behind the guard.

In `@apps/express/src/lib/get-session.ts`:
- Line 35: Replace the unsafe non-null assertion on exp in the expires
assignment by explicitly checking that the JWT claim exp exists and is a number
before converting it to an ISO string: in get-session.ts (the code that builds
the session object and sets expires), remove the `exp!` usage and if `exp` is a
finite number compute `new Date(exp * 1000).toISOString()`; otherwise set the
expires field to undefined (or omit it) so tokens without exp are handled
gracefully instead of producing a RangeError.

In `@apps/express/src/middleware/auth.ts`:
- Around line 37-45: The current loop in middleware/auth.ts uses
webResponse.headers.getSetCookie?.() ?? [value], but the fallback treats a
comma-joined Set-Cookie string as one cookie which corrupts cookies on older
Node.js; either remove the fallback entirely if you guarantee Node >= 18.14.1,
or replace the fallback with logic that splits the comma-joined string into
individual cookie strings (e.g., split the fallback value on ", " or a regex
that splits only between cookies) and then call res.append("Set-Cookie", cookie)
for each cookie using the result of webResponse.headers.getSetCookie(); update
the code around the webResponse.headers.entries() loop to use that corrected
fallback.
- Around line 16-29: The current code forwards original req.headers but always
serializes req.body to JSON when building the new globalThis.Request, causing a
Content-Type mismatch; before creating the Request in the block that builds
headers and body (references: req.headers, req.body, headers, new
globalThis.Request), detect when you serialize the body (method not "GET" or
"HEAD") and ensure the Content-Type header is set to "application/json" by
removing or overwriting any existing content-type entry (e.g.,
headers.set('content-type', 'application/json')) so the forwarded headers match
the JSON payload.

---

Nitpick comments:
In `@apps/express/.gitignore`:
- Around line 1-186: The .gitignore contains duplicate and irrelevant entries
merged from multiple templates; remove repeated entries (e.g., .DS_Store, dist,
.env, logs, *.log, .cache, node_modules) so each pattern appears only once and
delete framework-specific artifacts not used by an Express app (examples: .nuxt,
.nitro, .output, .tanstack, .vinxi, count.txt, todos.json) leaving only
Express-relevant ignores (node_modules, logs, coverage, .env, build/dist
outputs, editor caches). Ensure unique entries remain for patterns like .env,
.env.*, !.env.example, node_modules, coverage, .DS_Store, dist, .cache, logs,
and remove the duplicated blocks and unrelated framework lines.

In `@apps/express/src/auth.ts`:
- Line 4: The exported oauth array is listing every key from
builtInOAuthProviders (export const oauth) rather than the actual providers
configured in createAuth, causing UI to show non-functional options; update the
export to reflect the configured providers (e.g., derive the list from the
createAuth configuration or export a new name like availableOAuthProviders that
is populated from the actual auth config) or rename the existing export to make
its scope explicit (oauthAllProviders) and add a separate
configuredProviders/availableOAuthProviders export that reads the provider keys
used in createAuth so consumers only see functional providers.

In `@apps/express/src/lib/get-session.ts`:
- Around line 14-22: The manual cookie parsing in getSession (the cookieHeader
split/decodeURIComponent block) is redundant — replace that logic by reading the
parsed cookies from request.cookies (provided by cookie-parser middleware) and
use that Record<string,string> for session lookup; remove the custom split/map
pipeline in the getSession function and rely on req.cookies to avoid
double-parsing and handle edge cases, and ensure `@types/cookie-parser` is added
to devDependencies so TypeScript recognizes request.cookies on the Express
Request type.

In `@apps/express/src/middleware/auth.ts`:
- Around line 74-76: The catch block inside the auth middleware that currently
does "return res.status(500).json({ error: 'Internal Server Error' })" is
discarding the thrown error; modify that catch to log the error to stderr before
returning the 500 (use console.error(error) or the existing logger if available)
so runtime failures in the auth handler are visible; ensure you reference the
same catch block in the auth middleware (auth.ts) and keep the response behavior
unchanged except for the added logging.

In `@apps/express/src/middleware/with-auth.ts`:
- Around line 14-24: Add a TypeScript declaration merging so Express.Res.locals
is typed with the Session shape used in withAuth: create a global declaration
file that imports type { Session } from "@aura-stack/auth" and augments the
Express namespace with interface Locals { session?: Session }, then ensure the
declaration file is included in the TS build so downstream handlers reading
res.locals.session get compile-time safety; reference the withAuth middleware
and res.locals.session when applying this change.

In `@apps/express/test/index.test.ts`:
- Around line 56-64: Add a positive-path test to apps/express/test/index.test.ts
that exercises the withAuth middleware and the GET /api/protected handler:
generate a valid token with jose.encodeJWT, set it on the request as the cookie
name aura-auth.session_token, call supertest(app).get("/api/protected") with
.set("Cookie", [...]) and assert response.status is 200 and response.body
includes the expected message plus a session object containing the subject
(e.g., sub: "johndoe"); this ensures withAuth populates res.locals.session and
the handler returns it.

In `@apps/express/tsconfig.json`:
- Line 6: The tsconfig’s "include" only lists "src" so the test directory is
skipped by the type-check step; update the "include" array to also include
"test" (add "test") or create a new tsconfig.test.json that extends this
tsconfig and adds "test" to its "include", and ensure the CI/type-check script
(the `type-check` step invoking tsc --noEmit) uses the updated config so types
in apps/express/test/ are checked.

In `@apps/express/vitest.config.ts`:
- Around line 10-13: The vitest coverage block currently has enabled: true which
forces V8 instrumentation on every run; change the coverage config so it is
opt-in by removing or setting enabled to false in the coverage object (the
section containing provider: "v8" and enabled) and rely on the --coverage CLI
flag or CI config to enable coverage when needed; ensure the coverage provider
remains set to "v8" if you keep the block but make enabled opt-in.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/express/test/index.test.ts (1)

65-85: The aura-auth.csrf_token cookie on a GET request is unnecessary.

CSRF protection applies to state-changing methods (POST, PUT, DELETE). Setting a CSRF cookie on this GET request has no effect but may mislead readers into thinking CSRF validation occurs on reads. Consider removing it to keep the test focused, or add a separate POST-based test that actually exercises CSRF validation.

Suggested simplification
         const response = await supertest(app)
             .get("/api/protected")
-            .set("Cookie", [`aura-auth.session_token=${sessionToken}`, `aura-auth.csrf_token=valid_csrf_token`])
+            .set("Cookie", [`aura-auth.session_token=${sessionToken}`])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/test/index.test.ts` around lines 65 - 85, The test "returns
protected data when a valid session cookie is present" sets an unnecessary CSRF
cookie; remove the `aura-auth.csrf_token` entry from the Cookie header in that
test so it only sends `aura-auth.session_token` (or alternatively add a new POST
test that sends both `aura-auth.session_token` and `aura-auth.csrf_token` to
exercise CSRF validation). Locate the test block in
apps/express/test/index.test.ts (the async test named "returns protected data
when a valid session cookie is present") and update the supertest call to omit
the CSRF cookie or create a separate POST-based test to validate CSRF behavior.
apps/express/src/middlewares/auth.ts (1)

61-65: Redirect responses return a JSON body instead of a bare redirect.

For 3xx responses, this sends both the Location header (line 57) and a JSON body {message, location}. Standard HTTP clients follow the Location header and ignore the body, so this works, but it's unconventional. If this is intentional (e.g., for SPA clients that inspect the body), consider adding a brief comment explaining the design choice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/express/src/middlewares/auth.ts` around lines 61 - 65, The redirect
branch in the auth middleware currently returns a JSON body (uses
webResponse.headers.get("location") and res.json) for 3xx responses; change it
to perform a proper HTTP redirect by using the Express redirect mechanism or by
setting the status and Location header and ending the response (i.e., remove the
JSON body). Update the branch that checks webResponse.status >= 300 &&
webResponse.status < 400 so it calls res.redirect(location) or
res.status(webResponse.status).set('Location', location).end() instead of
res.json, and optionally add a comment if returning JSON for SPA clients is
intentional.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/express/src/server.ts`:
- Around line 1-3: The Vitest config for the express app lacks a resolve.alias
mapping for the "@/..." TypeScript path, so tests fail to resolve imports like
import { verifySession } from "@/lib/verify-session.js"; update
apps/express/vitest.config.ts (the defineConfig block) to add a resolve.alias
entry mapping "@" to the project's src directory (e.g., using
path.resolve(__dirname, "./src")) so Vitest can resolve "@/..." imports at test
runtime.

---

Duplicate comments:
In `@apps/express/package.json`:
- Line 11: The package.json "test" script references vitest but vitest is
missing from devDependencies; add "vitest" (and optional related packages like
"@vitest/coverage-c8" if used) to the devDependencies section of
apps/express/package.json so the test script can run reliably; update the
version to a suitable semver (e.g., "^1.0.0") consistent with the repo's test
tooling and run npm/yarn install to validate.
- Line 2: The package name "express" in apps/express package.json conflicts with
the official npm package; update the "name" field (currently "express") to a
scoped, unique identifier such as "@aura-stack/express-example" (or another
org-prefixed name) so pnpm workspace resolution won't shadow the Express
framework; ensure any workspace references (e.g., "express": "workspace:*") are
updated to the new name as well.

In `@apps/express/src/lib/get-session.ts`:
- Line 35: Remove the redundant non-null assertion on exp in the expires
assignment inside getSession (the guard if (!exp) return null already ensures
exp is defined); update the line that sets expires to use new Date(exp *
1000).toISOString() without the trailing ! so the code relies on the earlier
guard rather than force-asserting the value.

---

Nitpick comments:
In `@apps/express/src/middlewares/auth.ts`:
- Around line 61-65: The redirect branch in the auth middleware currently
returns a JSON body (uses webResponse.headers.get("location") and res.json) for
3xx responses; change it to perform a proper HTTP redirect by using the Express
redirect mechanism or by setting the status and Location header and ending the
response (i.e., remove the JSON body). Update the branch that checks
webResponse.status >= 300 && webResponse.status < 400 so it calls
res.redirect(location) or res.status(webResponse.status).set('Location',
location).end() instead of res.json, and optionally add a comment if returning
JSON for SPA clients is intentional.

In `@apps/express/test/index.test.ts`:
- Around line 65-85: The test "returns protected data when a valid session
cookie is present" sets an unnecessary CSRF cookie; remove the
`aura-auth.csrf_token` entry from the Cookie header in that test so it only
sends `aura-auth.session_token` (or alternatively add a new POST test that sends
both `aura-auth.session_token` and `aura-auth.csrf_token` to exercise CSRF
validation). Locate the test block in apps/express/test/index.test.ts (the async
test named "returns protected data when a valid session cookie is present") and
update the supertest call to omit the CSRF cookie or create a separate
POST-based test to validate CSRF behavior.

@vercel vercel bot temporarily deployed to Preview – auth February 20, 2026 02:33 Inactive
@vercel vercel bot temporarily deployed to Preview – auth-nextjs-demo February 20, 2026 02:33 Inactive
@halvaradop halvaradop merged commit 84c51b4 into master Feb 20, 2026
7 checks passed
@halvaradop halvaradop deleted the chore/add-express-integration-app branch February 20, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

examples Example code, demos, or sample implementations.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant