Skip to content

feat(backend): add API key auth middleware for operator-only endpoints - #139

Open
K1NGD4VID wants to merge 6 commits into
Stellar-Deejah:mainfrom
K1NGD4VID:Queue-routes
Open

feat(backend): add API key auth middleware for operator-only endpoints#139
K1NGD4VID wants to merge 6 commits into
Stellar-Deejah:mainfrom
K1NGD4VID:Queue-routes

Conversation

@K1NGD4VID

Copy link
Copy Markdown
Contributor

Summary

Adds API key authentication middleware (requireAuth) to protect operator-only endpoints (queue creation, advancement, closing, escrow release/refund/expire). Previously, any caller with network access could invoke these state-mutating endpoints without any credential.

Changes

backend/src/middleware/auth.ts (new)

  • Reads X-API-Key header and validates against OPERATOR_API_KEY environment variable
  • Uses crypto.timingSafeEqual for constant-time comparison (prevents timing oracle attacks)
  • Returns { error: { message: \Unauthorized\, status: 401 } } for missing/invalid/mismatched keys
  • Returns 401 when OPERATOR_API_KEY is not configured (fail-closed)

Protected routes

Route Method
/api/queues POST (create)
/api/queues/:id/advance POST
/api/queues/:id/close POST
/api/queues/:id/open-enrollment POST
/api/queues/:id/close-enrollment POST
/api/escrow/release POST
/api/escrow/refund POST
/api/escrow/expire POST

Unauthenticated routes (unchanged)

  • All GET routes (queue list, details, stats, escrow lookup)
  • POST /api/enrollments, DELETE /api/enrollments
  • POST /api/escrow/deposit
  • All /public routes

backend/.env.example

  • Added OPERATOR_API_KEY with documentation on generating strong keys (openssl rand -base64 32)

Configuration key: crypto.timingSafeEqual

Naive === string comparison short-circuits on the first mismatching character, leaking timing information that lets an attacker brute-force the key character by character over many requests. crypto.timingSafeEqual always compares every byte of both buffers regardless of where the first difference occurs, making it immune to timing side-channel attacks. Both buffers must be the same length — we compare lengths first (a fast-path rejection that does not leak the content), and only call timingSafeEqual when lengths match.

Tests

  • src/__tests__/routes/auth.route.test.ts — dedicated auth test file covering valid key (201), invalid key (401), missing key (401), no env var configured (401), all protected routes reject without key, and unauthenticated routes remain accessible
  • Updated queues.route.test.ts, escrow.route.test.ts, escrowRoutes.test.ts to set OPERATOR_API_KEY and send X-API-Key header on protected routes

Closes #50

Adds requireAuth middleware that validates X-API-Key header against
OPERATOR_API_KEY env var using crypto.timingSafeEqual to prevent
timing oracle attacks.

Protected routes (require valid X-API-Key):
- POST /api/queues (create)
- POST /api/queues/:id/advance
- POST /api/queues/:id/close
- POST /api/queues/:id/open-enrollment
- POST /api/queues/:id/close-enrollment
- POST /api/escrow/release
- POST /api/escrow/refund
- POST /api/escrow/expire

Unauthenticated routes remain open:
- GET /api/queues, GET /api/queues/:id, GET /api/queues/:id/stats
- POST /api/enrollments, DELETE /api/enrollments
- POST /api/escrow/deposit, GET /api/escrow/:id
- All /public routes

Returns 401 with { error: { message: 'Unauthorized', status: 401 } }
for missing or invalid keys.

Updates existing route tests to include API key header for protected
routes. Adds dedicated auth test file covering valid key, invalid key,
missing key, and no-OPERATOR_API_KEY-configured scenarios.

Closes Stellar-Deejah#50
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

@K1NGD4VID is attempting to deploy a commit to the Deejah Team on Vercel.

A member of the Team first needs to authorize it.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

- Remove merge conflict markers in escrow/queue route tests
- Fix createApp() call in index.ts (no arguments expected)
- Remove orphaned fn test_expire_position in test.rs
- Mock IntersectionObserver in frontend test setup
- Fix ambiguous findByRole('status') query in accessibility test
- Remove duplicate object keys in enrollment/escrow route tests
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
Comment thread backend/src/__tests__/routes/escrow.route.test.ts Fixed
- Fix merge conflict markers in escrow route test (release/refund/expire)
- Fix escrow deposit auth test with valid 56-char Stellar address
- Run cargo fmt on contracts/
- Remove --rm flag from docker run to allow log retrieval on failure
- Increase health check retries from 10 to 20 with 3s intervals (60s total)
- Add --start-period=10s to Docker HEALTHCHECK for backend startup grace period
- Fix HEALTHCHECK to use CommonJS require() instead of ES module import()
- Remove duplicate pnpm install line in Dockerfile
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.

Backend: Queue routes accept POST /queues without authentication — any caller can create, advance, or close any queue

2 participants