Skip to content
This repository was archived by the owner on Oct 9, 2026. It is now read-only.

feat(server): optional HTTP Basic Auth via AUTH_USERNAME/AUTH_PASSWORD - #137

Open
stantonb wants to merge 1 commit into
Ko-Insight:masterfrom
stantonb:feat/basic-auth
Open

stantonb wants to merge 1 commit into
Ko-Insight:masterfrom
stantonb:feat/basic-auth

Conversation

@stantonb

@stantonb stantonb commented Sep 28, 2026 •

Copy link
Copy Markdown

Refs #81, #12

What

Adds optional HTTP Basic Auth to the server so KoInsight can be exposed publicly without a reverse proxy. It is off unless both AUTH_USERNAME and AUTH_PASSWORD are set, so current deployments are unaffected.

  • Web UI: the browser shows its native login prompt. The web app calls the API with relative URLs, so the browser resends the credentials automatically. No frontend changes.
  • KOReader plugin: no changes. LuaSocket reads credentials from the URL and sends them as a Basic Authorization header (common/socket/http.lua), so the server URL becomes https://user:password@host. That's the same workaround people described in [Feature Request] - Add Native Password / Token Authentication (Required for Secure Public Self-Hosting) #81, now working without a proxy.
  • KoSync: the endpoints that already check x-auth-user/x-auth-key stay open (GET /users/auth, PUT /syncs/progress, GET /syncs/progress/:document), so KOReader progress sync keeps working unchanged. POST /users/create and GET /syncs/progress had no auth at all, so they now require Basic Auth. Otherwise anyone could register users or list every user's progress.

Credentials are compared in constant time (hash, then timingSafeEqual).

Changes

  • apps/server/src/auth/basic-auth-middleware.ts: the new middleware, plus tests
  • config.ts / app.ts: read the env vars and mount the middleware
  • README and .env.example: document the env vars and how to set up each client

Testing

  • 12 new unit tests, and the full server suite passes.
  • Deployed on Railway on top of v0.2.3. Without credentials, /, /api/books and /syncs/progress return 401 with a WWW-Authenticate header, and a wrong password also returns 401. With valid credentials, the UI and API return 200. KoSync's self-authenticated routes return their own JSON errors.
  • Real device: a Kindle Paperwhite 5 on KOReader v2026.07 with plugin 0.3.0 synced through https://user:pass@…. The device registered and its reading stats were uploaded.

Unrelated issue found while deploying

Current master crashes at startup in Docker: Cannot find module '@koinsight/common/utils/ranges'. #124 made books-service.ts import runtime code from packages/common, but the runner stage only copies node_modules, where @koinsight/common is a symlink to packages/common, which isn't copied. Even if it were, that package holds uncompiled .ts. v0.2.3 isn't affected. I left it out of this PR, and I'm happy to open a separate issue or PR.

A separate flaky test, also unrelated: stats-service.test.ts > mostPagesInADay sometimes hits a UNIQUE constraint on page_stat. It happens about once in 10 runs because random factory data collides.

🤖 Generated with Claude Code

When both env vars are set, the web UI and API require Basic Auth. The
KOReader plugin works unchanged by embedding credentials in the server URL
(LuaSocket sends them as a Basic Authorization header).

KoSync endpoints that already check x-auth-user/x-auth-key stay open so
KOReader progress sync keeps working. POST /users/create and
GET /syncs/progress, which had no auth, are now protected.

Refs Ko-Insight#81, Ko-Insight#12

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@stantonb

Copy link
Copy Markdown
Author

Tested on device and sync is all working with server and DB hosted on railway

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant