Skip to content

feat(auth-service): redirect / to /account#102

Merged
aspiers merged 1 commit intomainfrom
root-redirect-to-account
Apr 21, 2026
Merged

feat(auth-service): redirect / to /account#102
aspiers merged 1 commit intomainfrom
root-redirect-to-account

Conversation

@aspiers
Copy link
Copy Markdown
Contributor

@aspiers aspiers commented Apr 21, 2026

Summary

  • GET / on the auth service now 303-redirects to /account (which in turn bounces unauthenticated users to /account/login).
  • Previously the root path had no handler and returned Express's default 404, which was confusing for anyone bookmarking or mistyping the auth URL.
  • Adds a small createRootRouter() in packages/auth-service/src/routes/root.ts plus an integration test that spins up a minimal Express app and asserts status === 303 and location === '/account' with redirect: 'manual'.

Operator note

If you have an external healthcheck pointed at / expecting a 404, switch it to /health (unchanged, returns JSON status).

Test plan

  • `pnpm lint` clean
  • `pnpm typecheck` clean
  • `pnpm format:check` clean
  • `pnpm test` — full suite passes (595/595), new test included

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Root service URL now redirects (303) to the account page instead of returning an error.
    • Health checks should use the /health endpoint instead of the root path.
  • Tests

    • Added tests validating the redirect functionality.

The bare auth-service hostname previously returned a 404 "Cannot GET /"
page, which was confusing for users bookmarking or mistyping the URL.
Mount a tiny router that 303-redirects / to /account, matching the
redirect status used elsewhere in this service. /account itself enforces
auth and bounces to /account/login when unauthenticated, so the redirect
chain ends somewhere useful regardless of session state.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

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

Project Deployment Actions Updated (UTC)
epds-demo Ready Ready Preview, Comment Apr 21, 2026 3:59pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 21, 2026

🦋 Changeset detected

Latest commit: 548f4ad

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

The pull request adds a redirect handler for the auth service root URL. The GET / endpoint, previously unhandled and returning 404, now redirects with HTTP 303 status to /account. Changes include a new root router implementation, integration into the main app, a test verifying the redirect behavior, and changeset documentation.

Changes

Cohort / File(s) Summary
Changeset Documentation
.changeset/root-redirect-to-account.md
Documents the behavioral change that GET / on the auth service now redirects with 303 status to /account instead of returning 404. Notes that health checks should use /health endpoint instead.
Root Router Implementation
packages/auth-service/src/routes/root.ts
Introduces createRootRouter() function that exports an Express router with a single GET handler for / that responds with HTTP 303 redirect to /account.
App Integration
packages/auth-service/src/index.ts
Imports and mounts createRootRouter() before existing route handlers in the main Express application.
Root Router Test
packages/auth-service/src/__tests__/root-redirect.test.ts
Adds integration test that spins up a minimal Express app, mounts the root router, and verifies GET / returns 303 status with Location: /account header.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A redirect from root so neat,
To /account, where paths all meet,
No 404, just a gentle three-oh-three,
A hop and a skip, redirected with glee! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(auth-service): redirect / to /account' clearly and concisely describes the main change: adding a root route redirect from / to /account in the auth service.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch root-redirect-to-account

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.

@sonarqubecloud
Copy link
Copy Markdown

@railway-app
Copy link
Copy Markdown

railway-app Bot commented Apr 21, 2026

🚅 Deployed to the ePDS-pr-102 environment in ePDS

Service Status Web Updated (UTC)
@certified-app/demo untrusted ✅ Success (View Logs) Web Apr 21, 2026 at 4:02 pm
@certified-app/demo ✅ Success (View Logs) Web Apr 21, 2026 at 4:02 pm
@certified-app/pds-core ✅ Success (View Logs) Web Apr 21, 2026 at 4:02 pm
@certified-app/auth-service ✅ Success (View Logs) Web Apr 21, 2026 at 4:02 pm

@railway-app railway-app Bot temporarily deployed to ePDS / ePDS-pr-102 April 21, 2026 16:00 Destroyed
@coveralls-official
Copy link
Copy Markdown

Coverage Report for CI Build 24732639057

Coverage increased (+0.05%) to 42.568%

Details

  • Coverage increased (+0.05%) from the base build.
  • Patch coverage: 1 uncovered change across 1 file (4 of 5 lines covered, 80.0%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
packages/auth-service/src/index.ts 1 0 0.0%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 2273
Covered Lines: 985
Line Coverage: 43.33%
Relevant Branches: 1333
Covered Branches: 550
Branch Coverage: 41.26%
Branches in Coverage %: Yes
Coverage Strength: 3.64 hits per line

💛 - Coveralls

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
packages/auth-service/src/__tests__/root-redirect.test.ts (1)

7-44: Consider supertest to match the repo convention for route integration tests.

The coding guidelines call out supertest for covering route handlers, and it would let you drop the manual listen(0) / server.close() / ephemeral-port plumbing:

Proposed simplification
-import { afterAll, beforeAll, describe, expect, it } from 'vitest'
-import express, { type Express } from 'express'
-import type { AddressInfo } from 'node:net'
-import type { Server } from 'node:http'
-import { createRootRouter } from '../routes/root.js'
-
-let server: Server
-let baseUrl: string
-let app: Express
-
-beforeAll(async () => {
-  app = express()
-  app.use(createRootRouter())
-  await new Promise<void>((resolve) => {
-    server = app.listen(0, '127.0.0.1', () => {
-      resolve()
-    })
-  })
-  const addr = server.address() as AddressInfo
-  baseUrl = `http://127.0.0.1:${addr.port}`
-})
-
-afterAll(async () => {
-  await new Promise<void>((resolve, reject) => {
-    server.close((err) => {
-      if (err) reject(err)
-      else resolve()
-    })
-  })
-})
-
-describe('root router', () => {
-  it('redirects GET / to /account with 303 See Other', async () => {
-    const res = await fetch(`${baseUrl}/`, { redirect: 'manual' })
-    expect(res.status).toBe(303)
-    expect(res.headers.get('location')).toBe('/account')
-  })
-})
+import { describe, expect, it } from 'vitest'
+import express from 'express'
+import request from 'supertest'
+import { createRootRouter } from '../routes/root.js'
+
+describe('root router', () => {
+  it('redirects GET / to /account with 303 See Other', async () => {
+    const app = express()
+    app.use(createRootRouter())
+    const res = await request(app).get('/').redirects(0)
+    expect(res.status).toBe(303)
+    expect(res.headers.location).toBe('/account')
+  })
+})

The current test works and is correct; this is a convention alignment nit. As per coding guidelines: "Do not test route handlers with unit tests — cover them via supertest integration tests or e2e tests instead".

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

In `@packages/auth-service/src/__tests__/root-redirect.test.ts` around lines 7 -
44, Replace the manual listen/close ephemeral-port setup in
root-redirect.test.ts with supertest-based integration testing: import supertest
(or request) and use request(app) against the Express app created with
createRootRouter() (remove the beforeAll/afterAll server start/stop logic and
the baseUrl management), then call await request(app).get('/') with redirect
disabled and assert the response status is 303 and the Location header equals
'/account' to keep the existing expectations (refer to createRootRouter and the
test block that currently does fetch).
packages/auth-service/src/index.ts (1)

53-73: Root redirect is subject to CSRF + rate-limit middleware — consider mounting earlier.

createRootRouter() is mounted after csrfProtection, requestRateLimit, and createSecurityHeadersMiddleware. For a pure GET / → 303 that any visitor (including bookmarked/mistyped landings) can hit, this means:

  • Each GET / consumes a slot from the 60/min/IP bucket, so a refresh loop or a load balancer's liveness probe pointed at / could get 429s instead of a redirect.
  • It runs the CSRF + security-header work for what is effectively a static redirect.

CSRF for GET is typically a no-op, so that's not a correctness issue, but if you want / to behave like /health (cheap, always-on), consider mounting createRootRouter() before the middleware block — or at least before requestRateLimit. Keeping it where it is is also fine if you explicitly want / rate-limited; worth a conscious call.

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

In `@packages/auth-service/src/index.ts` around lines 53 - 73, The root router
(createRootRouter) is mounted after csrfProtection, requestRateLimit and
createSecurityHeadersMiddleware causing GET / to be subject to CSRF and
rate-limiting; move the createRootRouter() mounting earlier so the GET /
redirect is handled before requestRateLimit (and optionally before
csrfProtection/security headers) — i.e., call app.use(createRootRouter()) before
app.use(requestRateLimit(...)) (or before the entire middleware block) so the
cheap root redirect bypasses those middlewares unless you intentionally want it
rate-limited.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/auth-service/src/__tests__/root-redirect.test.ts`:
- Around line 7-44: Replace the manual listen/close ephemeral-port setup in
root-redirect.test.ts with supertest-based integration testing: import supertest
(or request) and use request(app) against the Express app created with
createRootRouter() (remove the beforeAll/afterAll server start/stop logic and
the baseUrl management), then call await request(app).get('/') with redirect
disabled and assert the response status is 303 and the Location header equals
'/account' to keep the existing expectations (refer to createRootRouter and the
test block that currently does fetch).

In `@packages/auth-service/src/index.ts`:
- Around line 53-73: The root router (createRootRouter) is mounted after
csrfProtection, requestRateLimit and createSecurityHeadersMiddleware causing GET
/ to be subject to CSRF and rate-limiting; move the createRootRouter() mounting
earlier so the GET / redirect is handled before requestRateLimit (and optionally
before csrfProtection/security headers) — i.e., call app.use(createRootRouter())
before app.use(requestRateLimit(...)) (or before the entire middleware block) so
the cheap root redirect bypasses those middlewares unless you intentionally want
it rate-limited.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03b4d359-b82f-4e58-a6e4-4c225305c0b4

📥 Commits

Reviewing files that changed from the base of the PR and between 70fb816 and 548f4ad.

📒 Files selected for processing (4)
  • .changeset/root-redirect-to-account.md
  • packages/auth-service/src/__tests__/root-redirect.test.ts
  • packages/auth-service/src/index.ts
  • packages/auth-service/src/routes/root.ts

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

LGTM — simple, self-contained redirect with a passing integration test.

Extended reasoning...

Overview

This PR touches four files: a new Express router (), its integration test, a one-line mount in , and a changeset entry. The sole behaviour change is replacing Express's default 404 on GET / with a 303 redirect to /account.

Security risks

None. The redirect target is a hard-coded relative path (/account); there is no user-controlled input and no open-redirect risk. The change does not touch auth, sessions, CSRF, or any permission-gated code.

Level of scrutiny

Low. This is a missing-route fill-in — the kind of one-liner that is hard to get wrong. The router is mounted first but only matches the exact path /, leaving all other routes unaffected.

Other factors

The PR ships with an integration test that verifies the exact status code (303) and Location header (/account) using redirect: 'manual'. The test plan notes 595/595 suite passes. The changeset includes a clear operator note about healthchecks. No outstanding reviewer comments.

@aspiers aspiers merged commit 1128699 into main Apr 21, 2026
19 of 22 checks passed
@aspiers aspiers deleted the root-redirect-to-account branch April 21, 2026 20:41
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.

1 participant