Skip to content

fix: resolve /api/auth/providers HTTP 404 by adding pass-through in Better Auth wildcard#1442

Merged
jaypatrick merged 3 commits intomainfrom
copilot/fix-auth-providers-404-error
Mar 28, 2026
Merged

fix: resolve /api/auth/providers HTTP 404 by adding pass-through in Better Auth wildcard#1442
jaypatrick merged 3 commits intomainfrom
copilot/fix-auth-providers-404-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 28, 2026

Description

Hono routes in registration order. app.get('/api/auth/providers', ...) was originally registered at ~line 635 — after the app.on(['POST', 'GET'], '/api/auth/*', ...) wildcard at ~line 356. The wildcard intercepted every /api/auth/* request first; Better Auth returned 404 (dur=0.0) because it has no knowledge of this custom endpoint. Both CI smoke tests were failing as a result.

A first attempt moved the handler before the wildcard, but that placed it before the CORS and unified auth/rate-limiting middleware, causing the endpoint to lose CORS headers and anonymous-tier rate limiting.

The correct fix keeps app.get('/api/auth/providers', ...) in the pre-auth meta section (after CORS + rate-limiting middleware) and adds an explicit return next() pass-through in the Better Auth wildcard for this path, so the wildcard never intercepts it.

Changes

  • Added return next() pass-through in the Better Auth wildcard handler for c.req.path === '/api/auth/providers', so the request falls through to the specific handler rather than returning 404
  • Added next parameter to the Better Auth wildcard handler signature to enable the pass-through
  • Kept app.get('/api/auth/providers', ...) in the pre-auth meta section (after CORS + rate-limiting middleware), preserving CORS header delivery and anonymous-tier rate limiting
// Better Auth wildcard now explicitly passes through for the custom endpoint:
app.on(['POST', 'GET'], '/api/auth/*', async (c, next) => {
    // /api/auth/providers is a custom public endpoint — pass through so it reaches
    // its registered handler with full CORS and rate-limiting middleware applied.
    if (c.req.path === '/api/auth/providers') return next();
    // ... Better Auth handling continues for all other /api/auth/* paths
});

// Handler stays in the pre-auth meta section (after middleware 3 + 4):
app.get('/api/auth/providers', (c) => handleAuthProviders(c.req.raw, c.env));

Testing

  • Unit tests added/updated
  • Manual testing performed
  • CI passes — smoke tests GET /api/auth/providers and SSR API proxy /api/auth/providers expected to go green

Zero Trust Architecture Checklist

Required for every PR touching worker/ or frontend/.

Worker / Backend

  • Every handler verifies auth before executing business logic — N/A (routing-order fix only; handleAuthProviders is a public read-only endpoint already in PRE_AUTH_PATHS)
  • CORS origin allowlist enforced (not *) on write/authenticated endpoints — N/A (no new endpoints; CORS coverage preserved by keeping handler after CORS middleware)
  • All secrets accessed via Worker Secret bindings (not [vars]) — N/A (no secret access changed)
  • All external inputs Zod-validated before use — N/A (handler returns static config, no external input)
  • All D1 queries use parameterized .prepare().bind() (no string interpolation) — N/A (no DB queries)
  • Security events emitted to Analytics Engine on auth failures — N/A (public endpoint, no auth)

Frontend / Angular

  • Protected routes have functional CanActivateFn auth guards — N/A
  • Auth tokens managed via Clerk SDK (not localStorage) — N/A
  • HTTP interceptor attaches ****** (no manual token passing) — N/A
  • API responses validated with Zod schemas before consumption — N/A

Frontend not touched. ZTA checklist completed above for worker/ change.

Original prompt

Problem

GET /api/auth/providers returns HTTP 404 with dur=0.0 in server-timing. This is proven by:

< HTTP/2 404
< server-timing: total;dur=0.0;desc="Total Response Time"
< content-length: 0

The zero duration means Hono matched the route and returned before any handler ran.

Root Cause

In worker/hono-app.ts, the app.get('/api/auth/providers', ...) handler is registered at line ~635 (after the routes sub-app declaration), but the Better Auth wildcard handler is registered at line ~356:

// Line ~356 — registered FIRST
app.on(['POST', 'GET'], '/api/auth/*', async (c) => {
    if (!c.env.BETTER_AUTH_SECRET) return c.notFound();  // ← returns 404 here!
    ...
});

// Line ~635 — registered TOO LATE, never reached
app.get('/api/auth/providers', (c) => handleAuthProviders(c.req.raw, c.env));

Because /api/auth/providers matches the /api/auth/* glob, Hono routes it to the Better Auth handler first. Since BETTER_AUTH_SECRET is set but Better Auth doesn't know about /api/auth/providers, it calls c.notFound() — returning a 404 with zero content before the actual handler ever runs.

Fix Required

In worker/hono-app.ts, move the app.get('/api/auth/providers', ...) registration to before the app.on(['POST', 'GET'], '/api/auth/*', ...) handler, so it takes priority.

Specifically:

  1. Find the app.on(['POST', 'GET'], '/api/auth/*', ...) block (currently around line 356).
  2. Insert the /api/auth/providers route handler immediately before it:
// ── 1b-pre. Public auth providers endpoint ────────────────────────────────────
// MUST be registered BEFORE the /api/auth/* wildcard handler below.
// Better Auth's wildcard catches /api/auth/providers and returns 404 because it
// does not know about this custom endpoint. Registering it first gives it priority.
app.get('/api/auth/providers', (c) => handleAuthProviders(c.req.raw, c.env));

// ── 1b. Better Auth route handler ─────────────────────────────────────────────
app.on(['POST', 'GET'], '/api/auth/*', async (c) => {
    ...
});
  1. Remove the duplicate app.get('/api/auth/providers', ...) registration that currently exists around line 635 (in the "Pre-auth API meta routes" section), along with its comment:
// DELETE these two lines around line 634-635:
// Public: returns which auth providers are active — used by frontend to conditionally render social login buttons.
app.get('/api/auth/providers', (c) => handleAuthProviders(c.req.raw, c.env));

Expected Result

  • GET /api/auth/providers → HTTP 200 with JSON body {"emailPassword":true,"github":false,"google":false,"mfa":true}
  • The CI smoke tests pass:
    • ❌ /api/auth/providers returned HTTP 404✅ /api/auth/providers returned HTTP 200
    • ❌ SSR API proxy /api/auth/providers returned HTTP 404✅ SSR API proxy /api/auth/providers returned HTTP 200

Files to Change

  • worker/hono-app.ts — move the app.get('/api/auth/providers', ...) call from ~line 635 to immediately before the app.on(['POST', 'GET'], '/api/auth/*', ...) block at ~line 356. No other files need changing.

Notes

  • handleAuthProviders is already imported at the top of the file (import { handleAuthProviders } from './handlers/auth-providers.ts') — no new imports needed.
  • This is a routing order fix only. No logic changes.
  • Do not modify the smoke test workflows — they are already correct and testing the right thing.

The following is the prior conversation context from the user's chat exploration (may be truncated):

Assistant: ## Why Brotli isn't supported

The root cause is a Cloudflare Workers runtime limitation. The CompressionStream Web API — which is what Hono's compress() middleware uses internally — only supports "gzip" and "deflate" in the Workers V8 isolate environment. This is a deliberate platform constraint, not a Hono limitation. From the Cloudflare community:

"Brotli is not available in CompressionStream on Workers. Only gzip and deflate are supported."

The only workaround would be to ship a Brotli WASM binary with the Worker, which adds bundle size and CPU overhead — almost certainly not worth it.


Performance impact of being gzip-only

Here's the honest breakdown for your specific use case:

Concern Impact
Bandwidth Gzip is ~10–25% worse compression ratio than Brotli for JSON/text. For your API responses (health JSON, metrics, compile output) this is meaningful but not catastrophic.
CPU on the Worker Actually better without Brotli — gzip compresses faster, especially for dynamic responses. Cloudflare's 10ms CPU limit makes this relevant.
Client decompression Negligible — both are near-instant on the client side.

The important nuance for your deployment

Cloudflare's CDN edge layer (the Cloudflare proxy in front of your Worker) does support Brotli for static assets served via Workers Sta...

This pull request was created from Copilot chat.


⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with Raycast.

@jaypatrick jaypatrick added bug Something isn't working deployment Deployment tasks labels Mar 28, 2026
@jaypatrick jaypatrick added this to the beta milestone Mar 28, 2026
Copilot AI changed the title [WIP] Fix 404 error for GET /api/auth/providers fix: register /api/auth/providers before Better Auth wildcard to resolve HTTP 404 Mar 28, 2026
Copilot AI requested a review from jaypatrick March 28, 2026 03:37
@jaypatrick jaypatrick requested a review from Copilot March 28, 2026 03:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a routing-order issue in the Worker’s Hono app where /api/auth/providers was being shadowed by the Better Auth /api/auth/* wildcard, causing CI smoke tests to fail with 404s.

Changes:

  • Registers GET /api/auth/providers before the Better Auth /api/auth/* wildcard route.
  • Removes the now-unreachable duplicate /api/auth/providers registration from the pre-auth meta routes section.
  • Updates section header labels for clarity around route ordering.

…h in Better Auth wildcard

Agent-Logs-Url: https://github.com/jaypatrick/adblock-compiler/sessions/164915a1-c772-4e2d-b477-9d02a275e39b

Co-authored-by: jaypatrick <1800595+jaypatrick@users.noreply.github.com>
Copilot AI changed the title fix: register /api/auth/providers before Better Auth wildcard to resolve HTTP 404 fix: resolve /api/auth/providers HTTP 404 by adding pass-through in Better Auth wildcard Mar 28, 2026
@jaypatrick jaypatrick marked this pull request as ready for review March 28, 2026 04:39
Copilot AI review requested due to automatic review settings March 28, 2026 04:39
@jaypatrick jaypatrick merged commit a0901c5 into main Mar 28, 2026
29 checks passed
@jaypatrick jaypatrick deleted the copilot/fix-auth-providers-404-error branch March 28, 2026 04:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment on lines +361 to +364
app.on(['POST', 'GET'], '/api/auth/*', async (c, next) => {
// Pass through for custom endpoint — let it reach its registered handler with
// full CORS and rate-limiting middleware applied.
if (c.req.path === '/api/auth/providers') return next();
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

No regression test covers the new pass-through behavior for /api/auth/providers. Since this endpoint was previously broken by the /api/auth/* wildcard routing order, please add a unit test (e.g., in worker/hono-app.test.ts) that asserts GET /api/auth/providers is not 404 and that it receives expected middleware effects (at least CORS header for an allowed Origin, and/or anonymous-tier rate limiting).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working deployment Deployment tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants