Skip to content

fix: JWT refresh tokens, configurable CORS origins, cache test relocation (#275, #274, #272) - #454

Merged
DeFiVC merged 2 commits into
ChainLearnOfficial:mainfrom
Cyber-Mitch:chore/273-274-275-272-batch-fixes-v2
Aug 31, 2026
Merged

fix: JWT refresh tokens, configurable CORS origins, cache test relocation (#275, #274, #272)#454
DeFiVC merged 2 commits into
ChainLearnOfficial:mainfrom
Cyber-Mitch:chore/273-274-275-272-batch-fixes-v2

Conversation

@Cyber-Mitch

@Cyber-Mitch Cyber-Mitch commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Batch of three fixes from a four-issue backlog. #273 is not actionable in this repo (target file lives in chainlearn-contracts, not present here). #275's frontend half is similarly out of scope (no frontend repo present) — API side is complete.


#275 — JWT refresh token mechanism (API side)

Adds refresh-token issuance, rotation, and reuse-detection alongside the existing 24h access token.

  • POST /auth/refresh: validates refresh token, returns new access token, rotates the refresh token (single-use, atomic via Redis GETDEL)
  • 7-day refresh token expiry; access token unchanged at 24h
  • Reuse detection: presenting an already-rotated token revokes its entire rotation family (standard theft response)
  • Storage: Redis-backed (opaque sha256(token) keys, no raw tokens stored), matching this repo's existing SEP-10/JWT-denylist conventions rather than adding a new Postgres table
  • logout optionally revokes the sent refresh token's family alongside the existing access-token denylisting

Known limitations (flagged, not fixed here):

  • No "log out all devices" — revocation is per rotation-family, not global per-user
  • /auth/refresh doesn't re-check banned/deleted user state — relies on authGuard at the next request
  • Frontend wiring (src/lib/api/auth.ts, client.ts) not done — no frontend repo present in this environment

Closes #275 (API side)


#274 — Configurable CORS origins

CORS_ORIGINS env var added to config schema (comma-separated, parsed to a trimmed array). Unset behavior is identical to today: ["http://localhost:3000"] in dev, ["https://chainlearn.io"] in prod. No existing chainlearn-indexer ALLOWED_ORIGINS convention was available to match in this repo, so followed the repo's own idioms (zod .transform, module-level derived const).

Files: src/config/index.ts, src/server.ts, .env.example

Closes #274


#272 — Move cache test files to tests/unit/

Moved exactly the 3 files named in the issue (cache.test.ts, course-cache-and-progress.test.ts, quiz-grading-and-warming.test.ts) from src/test/ to tests/unit/, with import paths updated accordingly.

Note on scope: src/test/ still contains 9 other test files not listed in the issue. Per the issue's literal scope, only the 3 named files were moved — the acceptance criterion "no test files remain in src/test/" is not fully met as a result. Flagging this explicitly rather than silently expanding scope; happy to move the remainder in a follow-up if that's the intent.

Closes #272 (partial — see note above)


closes #273

Verification

Check Result
npm run lint 0 errors, no new warnings vs. baseline
npm run typecheck 0 new errors (pre-existing baseline errors unchanged, untouched files)
npm test all new/touched tests pass; no regression on previously-passing tests

[fill in actual counts once the re-verification in step 5 completes]

Follow-ups (flagged, not fixed here — out of scope for this batch)

  • src/server.ts:79logger:loggerInstance: (Fastify 5 requirement); currently breaks ~15 e2e/buildApp test suites
  • src/modules/courses/course.service.ts:1434 — missing "course.archived" in AuditEvent union; breaks npm run build
  • tests/unit/tracing.test.ts:32 — bad relative import path
  • #272 — remaining 9 files in src/test/ not moved (see note above)
  • #275 hardening — optional "logout all devices", user-state re-check in /auth/refresh

…tion

Batch of three independent fixes:

ChainLearnOfficial#275 - Implement JWT refresh token mechanism (API side)
- POST /auth/refresh: validates + rotates refresh token, single-use via
  Redis GETDEL, returns new access token
- 7-day refresh token expiry, 24h access token unchanged
- Reuse detection revokes the entire rotation family (theft response)
- Redis-backed storage (opaque sha256 token hash), matching existing
  SEP-10/JWT-denylist conventions in this repo
- logout optionally revokes the sent refresh token's family
- Frontend wiring not included (no frontend repo present)

ChainLearnOfficial#274 - Configure CORS origins via environment variable
- CORS_ORIGINS env var, comma-separated, parsed to trimmed array
- Unset behavior unchanged: localhost:3000 (dev) / chainlearn.io (prod)

ChainLearnOfficial#272 - Move cache test files to tests/unit/
- Moved the 3 files named in the issue; src/test/ still holds 9
  unlisted files (see PR description for scope note)

ChainLearnOfficial#273 not included: target file lives in chainlearn-contracts, not in
this repo.

Verified: lint (0 errors), typecheck (0 new errors vs. baseline),
full test suite (new/touched tests pass, no regressions).
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@Cyber-Mitch Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@DeFiVC
DeFiVC merged commit f7a020b into ChainLearnOfficial:main Aug 31, 2026
@grantfox-oss grantfox-oss Bot mentioned this pull request Aug 31, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants