Fix authentication bypass and require SUPABASE_JWT_SECRET#384
Conversation
|
@vipul674 is attempting to deploy a commit to the firefistisdead's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughServer startup now requires SUPABASE_JWT_SECRET and fails fast if missing. The requireSupabaseAuth middleware always attempts JWT verification, returning 500 for missing configuration and 401 for invalid tokens. Tests save/restore the env var, add a startup regression, and exercise middleware behaviors. ChangesJWT Secret Enforcement and Verification
🎯 3 (Moderate) | ⏱️ ~20 minutes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Enforces that SUPABASE_JWT_SECRET is configured at startup and required for verifying tokens in the requireSupabaseAuth middleware, closing a gap where requests could pass auth without cryptographic verification.
Changes:
- Fail-fast at server boot if
SUPABASE_JWT_SECRETis not set. - Always verify JWTs in
requireSupabaseAuth; return 500 if the secret is missing at request time. - Update tests to set/restore
SUPABASE_JWT_SECRETso the module loads under test.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| server.js | Adds startup check for SUPABASE_JWT_SECRET and requires JWT verification in requireSupabaseAuth. |
| server.test.js | Sets and restores SUPABASE_JWT_SECRET env var so tests can load the server module. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!secret) { | ||
| // Server misconfiguration: SUPABASE_JWT_SECRET must be set. | ||
| return res.status(500).json({ error: "Server misconfiguration: missing SUPABASE_JWT_SECRET" }); | ||
| } |
| return res.status(500).json({ error: "Server misconfiguration: missing SUPABASE_JWT_SECRET" }); | ||
| } | ||
|
|
||
| const jwt = require("jsonwebtoken"); |
| const SUPABASE_JWT_SECRET = process.env.SUPABASE_JWT_SECRET; | ||
| if (!SUPABASE_JWT_SECRET) { | ||
| throw new Error("SUPABASE_JWT_SECRET missing in .env – required for /process-from-url authentication"); | ||
| } |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
server.test.js (1)
10-15: ⚡ Quick winAdd regression tests for the auth contract, not just env plumbing.
These hooks keep the suite green, but they still don't assert the security behavior this PR is fixing. Please add one test for startup failing without
SUPABASE_JWT_SECRET, and one/process-from-urltest that rejects a validly signed non-user token (for examplerole: "anon") as well as a malformed token. Supabase documents separateanon,authenticated, andservice_roleJWT roles, so that distinction is the regression surface here. (supabase.com)Also applies to: 31-35
🤖 Prompt for 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. In `@server.test.js` around lines 10 - 15, Add regression tests to server.test.js: add an "it" that ensures server startup fails (or returns error) when process.env.SUPABASE_JWT_SECRET is unset by clearing SUPABASE_JWT_SECRET (using originalSupabaseJwtSecret) and attempting the startup path used in tests (require/startServer or the same initialization used by existing tests), asserting it throws or exits; and add a "/process-from-url" test that POSTs to the /process-from-url handler using a JWT signed with SUPABASE_JWT_SECRET but with payload role: "anon" (and another request with a malformed token) and assert the endpoint rejects both (HTTP 401/403 or error response) to confirm non-user and malformed tokens are rejected. Use the same test helpers and teardown in the file and restore process.env.SUPABASE_JWT_SECRET after each test.server.js (1)
21-24: ⚡ Quick winFail fast on startup, not on import.
This guard runs during
require("./server.js"), so anything that importsappnow hard-fails before it can configure test/runtime env. Moving the throw into therequire.main === modulestartup path preserves the security guarantee without breaking non-startup consumers.♻️ Proposed refactor
-const SUPABASE_JWT_SECRET = process.env.SUPABASE_JWT_SECRET; -if (!SUPABASE_JWT_SECRET) { - throw new Error("SUPABASE_JWT_SECRET missing in .env – required for /process-from-url authentication"); -} +const getSupabaseJwtSecret = () => (process.env.SUPABASE_JWT_SECRET || "").trim();if (require.main === module) { requireInternalRagToken(); + if (!getSupabaseJwtSecret()) { + throw new Error("SUPABASE_JWT_SECRET missing in .env – required for /process-from-url authentication"); + } (async () => {🤖 Prompt for 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. In `@server.js` around lines 21 - 24, The code currently throws when SUPABASE_JWT_SECRET is missing at module import time (const SUPABASE_JWT_SECRET ... throw new Error(...)); move this guard into the startup execution path so imports don't fail: remove the top-level throw and instead perform the check inside the module’s entry/start block (use if (require.main === module) { if (!SUPABASE_JWT_SECRET) throw new Error(...) } or add the same check at the start of the startServer / main function) ensuring the error is still raised on actual process startup while allowing other code to require the module for tests or configuration.
🤖 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 `@server.js`:
- Around line 729-738: After verifying the JWT in requireSupabaseAuth, validate
Supabase-specific claims on the decoded token (the object assigned to req.user
from jwt.verify) and reject non-user tokens: ensure req.user.role ===
"authenticated" (and optionally req.user.aud === "authenticated") and return a
401 JSON error if these checks fail; keep the jwt.verify(token, secret) call but
add explicit claim checks to prevent anon or service_role tokens from being
accepted.
---
Nitpick comments:
In `@server.js`:
- Around line 21-24: The code currently throws when SUPABASE_JWT_SECRET is
missing at module import time (const SUPABASE_JWT_SECRET ... throw new
Error(...)); move this guard into the startup execution path so imports don't
fail: remove the top-level throw and instead perform the check inside the
module’s entry/start block (use if (require.main === module) { if
(!SUPABASE_JWT_SECRET) throw new Error(...) } or add the same check at the start
of the startServer / main function) ensuring the error is still raised on actual
process startup while allowing other code to require the module for tests or
configuration.
In `@server.test.js`:
- Around line 10-15: Add regression tests to server.test.js: add an "it" that
ensures server startup fails (or returns error) when
process.env.SUPABASE_JWT_SECRET is unset by clearing SUPABASE_JWT_SECRET (using
originalSupabaseJwtSecret) and attempting the startup path used in tests
(require/startServer or the same initialization used by existing tests),
asserting it throws or exits; and add a "/process-from-url" test that POSTs to
the /process-from-url handler using a JWT signed with SUPABASE_JWT_SECRET but
with payload role: "anon" (and another request with a malformed token) and
assert the endpoint rejects both (HTTP 401/403 or error response) to confirm
non-user and malformed tokens are rejected. Use the same test helpers and
teardown in the file and restore process.env.SUPABASE_JWT_SECRET after each
test.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 960e9956-071d-4b57-a2d9-b7067767c112
📒 Files selected for processing (2)
server.jsserver.test.js
| if (!secret) { | ||
| // Server misconfiguration: SUPABASE_JWT_SECRET must be set. | ||
| return res.status(500).json({ error: "Server misconfiguration: missing SUPABASE_JWT_SECRET" }); | ||
| } | ||
|
|
||
| const jwt = require("jsonwebtoken"); | ||
| try { | ||
| req.user = jwt.verify(token, secret); | ||
| } catch (err) { | ||
| return res.status(401).json({ error: "Invalid token" }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the exact region around the reported lines
sed -n '700,780p' server.js | nl -ba
# Find all usages of req.user to understand what claims are relied on
rg -n "req\.user" server.js
# Find where token is sourced and what middleware this snippet belongs to
rg -n "const token|token\s*=" server.js
rg -n "Authorization|bearer|req\.headers" server.js
# Show surrounding auth middleware definition (helps confirm expectations)
rg -n "verify|jsonwebtoken|SUPABASE_JWT_SECRET" server.jsRepository: FireFistisDead/pdf-qa-bot
Length of output: 112
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Confirm file exists
ls -la server.js
# Show the exact region around the reported lines with line numbers (no `nl` needed)
sed -n '700,780p' server.js | awk '{printf "%6d %s\n", NR+699, $0}'
# Find all usages of req.user to understand what claims are relied on
rg -n "req\.user" server.js
# Find where token is sourced and what middleware this snippet belongs to
rg -n "(token\s*=|const token|Authorization|bearer|req\.headers)" server.js
# Find where jsonwebtoken is used and where SUPABASE_JWT_SECRET is referenced
rg -n "(jsonwebtoken|jwt\.verify|SUPABASE_JWT_SECRET)" server.js
# Show any claim/role/aud checks nearby (if any)
rg -n "(role|aud|sub|authenticated|service_role|anon)" server.jsRepository: FireFistisDead/pdf-qa-bot
Length of output: 4551
🌐 Web query:
Supabase JWT claims role aud anon service_role authenticated
💡 Result:
In Supabase Auth JWTs, the relevant claims are: 1) role - "anon": anonymous user - "authenticated": authenticated user - "service_role": service role (intended for server-side use) [1] 2) aud (audience) - "authenticated": for authenticated user tokens - "anon": for anonymous user tokens [1] So the typical combinations you’ll see are: - Anonymous access: role = "anon" and aud = "anon" [1] - Authenticated user access: role = "authenticated" and aud = "authenticated" [1] - Service role: role = "service_role" (service-role token example shown includes role="service_role"; aud is part of the required JWT claims schema but the key point is the role value) [1] If you’re decoding/inspecting JWTs: Supabase documents these as standard JWT claims used for authorization with Postgres/RLS via the role claim [2].
Citations:
🌐 Web query:
Supabase JWT signing algorithm HS256 RS256 project JWT secret jwt.verify algorithms
💡 Result:
Supabase supports multiple algorithms for signing and verifying JSON Web Tokens (JWTs), but it strongly recommends using asymmetric algorithms over symmetric ones [1][2]. Asymmetric Algorithms (Recommended) Supabase supports asymmetric signing keys, which provide improved security and performance compared to shared secrets [1][3]. - ES256 (NIST P-256 Curve): This is the recommended algorithm. It is faster than RSA and produces shorter signatures, which is beneficial for reducing data transfer sizes and cookie management [1][4]. - RS256 (RSA 2048): A widely supported public-key algorithm, though generally slower than elliptic curves [1][4]. Symmetric Algorithm (Not Recommended for Production) - HS256 (HMAC with SHA-256): This uses a shared secret [1][5]. Supabase explicitly advises against using HS256 for production applications because there is no public key counterpart, making key revocation more difficult and potentially exposing your project to security risks [1][4][6]. JWT Verification - Preferred Method: For asymmetric keys, Supabase recommends using supabase.auth.getClaims() or high-quality JWT verification libraries [2][3]. These libraries verify the token locally using public keys fetched from your project's JWKS endpoint (/.well-known/jwks.json), avoiding the need to make network calls to the Auth server [2][3][7]. - Legacy/HS256 Verification: If you are still using a shared secret (HS256), the recommended approach is to verify the token by sending a request to the Auth server (e.g., via getUser()), rather than verifying it locally with the secret [2][6]. Security Best Practices - Algorithm Pinning: Always pin the expected algorithm in your verification code (e.g., algorithms: ["RS256"]) to prevent algorithm confusion attacks, where an attacker might attempt to force a symmetric signature using an asymmetric public key [8][5]. - Avoid alg: none: Explicitly reject tokens with the none algorithm [5][9]. - Use JWKS: Leverage the public JSON Web Key Set (JWKS) endpoint provided by your project for secure, automated public key discovery when using asymmetric algorithms [2][7].
Citations:
- 1: https://supabase.com/docs/guides/auth/signing-keys
- 2: https://supabase.com/docs/guides/auth/jwts
- 3: https://supabase.com/changelog/29289-supabase-auth-asymmetric-keys-support-in-2025
- 4: https://github.com/supabase/supabase/blob/master/apps/docs/content/guides/auth/signing-keys.mdx
- 5: https://dev.to/havenmessenger/jwt-security-pitfalls-the-mistakes-that-keep-breaking-tokens-9dj
- 6: https://github.com/supabase/supabase/blob/master/apps/docs/content/guides/auth/jwts.mdx
- 7: https://supabase.com/blog/jwt-signing-keys
- 8: https://dev.to/ssojet/jwt-kid-header-missing-what-it-means-and-how-to-fix-it-fast-3cgl
- 9: https://dev.to/snappy_tools/jwts-explained-whats-inside-that-token-and-how-to-read-it-2l80
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for SUPABASE_JWT_SECRET usage and any documentation/comments about JWT algorithm/role handling
rg -n "SUPABASE_JWT_SECRET|jwt\.verify|jsonwebtoken|role\"|aud\"|service_role|anon\"|authenticated\"" -S .
# Show server.js around token verification (more context)
sed -n '680,760p' server.js
# Locate any config/env/doc mentioning JWT algorithm (HS256/RS256) or Supabase Auth JWT structure
rg -n "HS256|RS256|JWKS|well-known/jwks|getClaims|getUser|supabase\.auth" -S . || true
# List repository top-level files that might contain auth instructions
ls -ლაRepository: FireFistisDead/pdf-qa-bot
Length of output: 50465
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,120p' src/middleware/authMiddleware.js
echo "----"
sed -n '1,220p' src/controllers/authController.js
echo "----"
sed -n '1,140p' server.test.js
echo "----"
rg -n "authMiddleware|requireSupabaseAuth|req\.user|jwt\.verify" -S server.js src/middleware src/controllers server.test.js
echo "----"
rg -n "role\"|aud\"|service_role|anon\"|authenticated\"|sub\"" -S server.js src/middleware src/controllersRepository: FireFistisDead/pdf-qa-bot
Length of output: 8088
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find where /process-from-url is called and what Authorization header is set
rg -n "process-from-url" -S . --glob='*.js' --glob='*.jsx' --glob='*.ts' --glob='*.tsx'
rg -n "SUPABASE_JWT_SECRET|requireSupabaseAuth|Bearer " -S server.js frontend src --glob='*.js' --glob='*.jsx' --glob='*.ts' --glob='*.tsx'
# Locate ragAuthHeaders implementation (to ensure it's not being conflated with Supabase JWT auth)
rg -n "function ragAuthHeaders|ragAuthHeaders" -S server.js src --glob='*.js'
# Check if `req.user` is used anywhere besides assignment
rg -n "req\.user" server.js src --glob='*.js'Repository: FireFistisDead/pdf-qa-bot
Length of output: 1899
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check for any documentation / config references
rg -n "SUPABASE_JWT_SECRET|process-from-url|requireSupabaseAuth|access_token|role\"|aud\"" -S . --glob='README*' --glob='*.md' --glob='*.js' --glob='*.ts'
# Show the frontend call site with surrounding context (ragService.js)
sed -n '1,120p' frontend/src/services/ragService.js
# Extract any comments around /process-from-url auth expectations
rg -n "process-from-url" -n server.js
sed -n '700,900p' server.jsRepository: FireFistisDead/pdf-qa-bot
Length of output: 12346
Enforce Supabase JWT claim checks in requireSupabaseAuth (reject role=anon / non-user tokens)
requireSupabaseAuth only does jwt.verify(token, secret) and assigns the result to req.user without checking Supabase authorization claims (role / aud). That means an anon (and potentially service_role) JWT can pass this middleware.
After jwt.verify, require user-level claims, e.g. claims.role === "authenticated" (and typically claims.aud === "authenticated"), otherwise return 401. See Supabase JWT fields: https://supabase.com/docs/guides/auth/jwt-fields
🤖 Prompt for 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.
In `@server.js` around lines 729 - 738, After verifying the JWT in
requireSupabaseAuth, validate Supabase-specific claims on the decoded token (the
object assigned to req.user from jwt.verify) and reject non-user tokens: ensure
req.user.role === "authenticated" (and optionally req.user.aud ===
"authenticated") and return a 401 JSON error if these checks fail; keep the
jwt.verify(token, secret) call but add explicit claim checks to prevent anon or
service_role tokens from being accepted.
| requireInternalRagToken(); | ||
| if (!SUPABASE_JWT_SECRET) { | ||
| throw new Error("SUPABASE_JWT_SECRET missing in .env – required for /process-from-url authentication"); | ||
| } |
| test("accepts valid token and proceeds to route handler", async () => { | ||
| const token = jwt.sign({ role: "authenticated" }, process.env.SUPABASE_JWT_SECRET); | ||
| const res = await fetch(`${baseUrl}/process-from-url`, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: `Bearer ${token}`, | ||
| }, | ||
| body: JSON.stringify({ url: "https://example.com/test.pdf" }), | ||
| }); | ||
| assert.notEqual(res.status, 401, "Valid token should not be rejected"); | ||
| }); |
| return res.status(500).json({ error: "Server misconfiguration: missing SUPABASE_JWT_SECRET" }); | ||
| } | ||
|
|
||
| const jwt = require("jsonwebtoken"); |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
server.test.js (1)
723-794: ⚡ Quick winStrengthen auth regression coverage in the new middleware suite.
The positive-path test is too permissive (
not 401), and the middleware’s explicit 500 misconfiguration branch is still untested. Tightening both will make this security fix less brittle.Suggested test hardening
test("accepts valid token and proceeds to route handler", async () => { const token = jwt.sign({ role: "authenticated" }, process.env.SUPABASE_JWT_SECRET); const res = await fetch(`${baseUrl}/process-from-url`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ url: "https://example.com/test.pdf" }), }); - assert.notEqual(res.status, 401, "Valid token should not be rejected"); + assert.equal(res.status, 403); + const data = await res.json(); + assert.equal(data.error, "URL host is not allowed."); }); + + test("returns 500 when SUPABASE_JWT_SECRET is missing at request time", async () => { + const original = process.env.SUPABASE_JWT_SECRET; + delete process.env.SUPABASE_JWT_SECRET; + try { + const res = await fetch(`${baseUrl}/process-from-url`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer placeholder", + }, + body: JSON.stringify({ url: "https://example.com/test.pdf" }), + }); + assert.equal(res.status, 500); + const data = await res.json(); + assert.match(data.error, /missing SUPABASE_JWT_SECRET/i); + } finally { + if (original === undefined) { + delete process.env.SUPABASE_JWT_SECRET; + } else { + process.env.SUPABASE_JWT_SECRET = original; + } + } + });🤖 Prompt for 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. In `@server.test.js` around lines 723 - 794, The positive-path test in the requireSupabaseAuth suite is too weak (assert.notEqual(res.status, 401)); update the "accepts valid token" case to assert the exact successful status (e.g., 200) and verify expected response content from the /process-from-url route so the middleware truly allows valid tokens. Also add a new test that simulates the middleware misconfiguration by temporarily deleting or clearing process.env.SUPABASE_JWT_SECRET, calling POST /process-from-url, and asserting the middleware returns the explicit 500 misconfiguration response (status 500 and the middleware's misconfiguration error body) to cover the 500 branch in requireSupabaseAuth.
🤖 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.
Nitpick comments:
In `@server.test.js`:
- Around line 723-794: The positive-path test in the requireSupabaseAuth suite
is too weak (assert.notEqual(res.status, 401)); update the "accepts valid token"
case to assert the exact successful status (e.g., 200) and verify expected
response content from the /process-from-url route so the middleware truly allows
valid tokens. Also add a new test that simulates the middleware misconfiguration
by temporarily deleting or clearing process.env.SUPABASE_JWT_SECRET, calling
POST /process-from-url, and asserting the middleware returns the explicit 500
misconfiguration response (status 500 and the middleware's misconfiguration
error body) to cover the 500 branch in requireSupabaseAuth.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 26e571b3-3035-4995-bffa-5f86ccecb665
📒 Files selected for processing (2)
server.jsserver.test.js
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
server.test.js:1
- This assertion only checks that the response is not a 401 with a specific error string. A regression where the middleware rejects valid tokens with a different status (e.g. 500 or 403) or a different message would still pass. Consider asserting positively against the expected downstream handler behavior (e.g. status code or response shape) for a valid token to provide stronger coverage.
const { test, describe, before, after } = require("node:test");
| const RAG_SERVICE_URL = process.env.RAG_SERVICE_URL || "http://localhost:5000"; | ||
| const getInternalRagToken = () => (process.env.INTERNAL_RAG_TOKEN || "").trim(); | ||
| const PORT = process.env.PORT || 4000; | ||
| const SUPABASE_JWT_SECRET = process.env.SUPABASE_JWT_SECRET; |
| test("returns 500 when SUPABASE_JWT_SECRET is missing at request time", async () => { | ||
| const express = require("express"); | ||
| const testApp = express(); | ||
| testApp.use(express.json()); | ||
| const testMiddleware = (req, res, next) => { |
…tured const
- Hoist `require('jsonwebtoken')` to top of file so it loads once
rather than on every authenticated request (Copilot feedback).
- Capture SUPABASE_JWT_SECRET with .trim() to reject whitespace-only
values and read from the captured constant in requireSupabaseAuth
instead of process.env on every request, matching the INTERNAL_RAG_TOKEN
pattern and avoiding drift if the env var is mutated after module load
(Copilot feedback).
- No behavior change: all 47 tests pass.
|
@FireFistisDead Quick update — pushed commit
The only remaining CI signal is the Vercel preview deploy gate which needs your team to authorize Vercel for the org (one-time setup). Happy to help debug if you want — otherwise the PR is mergeable from a code/CI perspective. Let me know if you'd like me to also add a |
|
@FireFistisDead Please review and let me know for any changes. |
Summary
requireSupabaseAuthmiddleware by rejecting requests whenSUPABASE_JWT_SECRETis missing (HTTP 500).SUPABASE_JWT_SECRETis not set, preventing server from running with insecure configuration.SUPABASE_JWT_SECRETenvironment variable, ensuring tests pass.Related issue
Closes #342
Testing
Checklist:
Screenshots / recordings
N/A (backend security fix)
Notes
SUPABASE_JWT_SECRETa required environment variable for the Express server. Deployments must set this variable to a strong secret.Security
Description
Fixed authentication bypass vulnerability where missing
SUPABASE_JWT_SECRETallowed any Bearer token to be accepted. Now the middleware returns HTTP 500 when the secret is missing, and the server refuses to start without it.Testing & Verification
SUPABASE_JWT_SECRETis missing.GSSoC 2026 Compliance & Transparency
Summary by CodeRabbit
Bug Fixes
Tests