Skip to content

Optional HTTP Basic Authorization configuration#619

Merged
bordalix merged 2 commits into
masterfrom
basic-auth
May 18, 2026
Merged

Optional HTTP Basic Authorization configuration#619
bordalix merged 2 commits into
masterfrom
basic-auth

Conversation

@s373nZ
Copy link
Copy Markdown
Contributor

@s373nZ s373nZ commented May 18, 2026

Adds optional configuration of HTTP basic authentication by setting BASIC_AUTH_USERNAME and BASIC_AUTH_PASSWORD as environment variables.

Support for both the Vite server via a plugin, as well as Cloudflare Pages middleware.

Allows for the protection of private wallet instances.

Summary by CodeRabbit

  • New Features
    • Added HTTP Basic Authentication protection. When configured via environment variables, the application requires valid credentials for all requests.

Review Change Stack

@s373nZ s373nZ requested a review from bordalix May 18, 2026 10:15
@s373nZ s373nZ self-assigned this May 18, 2026
@s373nZ s373nZ added the enhancement New feature or request label May 18, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Warning

Rate limit exceeded

@s373nZ has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 47 minutes and 15 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef9b9f9f-76dc-4801-be22-60c1284df023

📥 Commits

Reviewing files that changed from the base of the PR and between 2ee081b and 6acd835.

📒 Files selected for processing (2)
  • functions/_middleware.ts
  • plugins/vite-plugin-basic-auth.ts

Walkthrough

This PR adds HTTP Basic Auth support across the application by introducing a Vite plugin for dev/preview servers and a Cloudflare Pages middleware for production edge requests. Both implementations read credentials from environment variables and are no-ops if either credential is unset.

Changes

HTTP Basic Authentication across Vite and Cloudflare

Layer / File(s) Summary
Vite plugin for basic auth
plugins/vite-plugin-basic-auth.ts
Implements basicAuthMiddleware() helper that validates the Authorization header and a basicAuth() Vite plugin that conditionally registers the middleware on dev and preview servers when BASIC_AUTH_USERNAME and BASIC_AUTH_PASSWORD environment variables are set.
Vite configuration integration
vite.config.ts
Imports and registers the basicAuth() plugin in the Vite configuration plugins array.
Cloudflare Pages edge middleware
functions/_middleware.ts
Exports an onRequest handler that conditionally enforces HTTP Basic Auth on every request by reading credentials from context.env, comparing the Authorization header against the expected Base64-encoded token, and returning 401 with WWW-Authenticate header on mismatch.

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Optional HTTP Basic Authorization configuration' accurately summarizes the main change: adding optional HTTP Basic Auth support via environment variables across dev/preview servers and Cloudflare Pages.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch basic-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@arkanaai arkanaai Bot left a comment

Choose a reason for hiding this comment

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

Code Review — #619

Scope: Frontend deployment auth — NOT protocol-critical. No VTXO, signing, or round-lifecycle code touched. This adds optional HTTP Basic Auth gating on the wallet SPA bundle (defense-in-depth for private instances).


🔴 Must Fix

1. PagesFunction type is unresolved — build will break
functions/_middleware.ts:18PagesFunction is used but never imported, and @cloudflare/workers-types is not in package.json or referenced in tsconfig.json. The tsconfig include: ["**/*.ts"] will pick up this file during type-checking.

Fix: either add @cloudflare/workers-types as a dev dependency and include it in tsconfig compilerOptions.types, or exclude functions/ from tsconfig and add a separate functions/tsconfig.json for CF Pages.

2. Timing-unsafe credential comparison
functions/_middleware.ts:27 and plugins/vite-plugin-basic-auth.ts:18 — Both use === to compare the Authorization header against the expected value. This is theoretically vulnerable to timing side-channel attacks.

Practical risk is low over HTTP (network jitter dwarfs the timing delta), but it's trivial to fix and this is an auth boundary:

// Cloudflare Workers (functions/_middleware.ts)
// Use crypto.timingSafeEqual via the Web Crypto API or a polyfill
const encoder = new TextEncoder()
const a = encoder.encode(auth)
const b = encoder.encode(expected)
if (a.byteLength !== b.byteLength || !crypto.subtle.timingSafeEqual(a, b)) return unauthorized()

// Node/Vite (plugins/vite-plugin-basic-auth.ts)
import { timingSafeEqual } from 'node:crypto'
const a = Buffer.from(auth ?? '')
const b = Buffer.from(expected)
if (a.byteLength !== b.byteLength || !timingSafeEqual(a, b)) return unauthorized()

🟡 Should Fix

3. No brute-force protection
Neither implementation has rate limiting. An attacker can hammer the endpoint with credential guesses. For Cloudflare, consider Cloudflare's built-in rate limiting rules. For the Vite dev server this matters less, but worth noting.

4. No tests
No test coverage for either the Vite plugin or the Cloudflare middleware. At minimum, unit tests should cover:

  • Passthrough when env vars are unset
  • 401 when no Authorization header is provided
  • 401 when wrong credentials are provided
  • 200 (pass-through to next()) when correct credentials are provided

✅ Looks Good

  • Plugin ordering in vite.config.ts — auth runs first, correct.
  • No-op when env vars are unset — clean opt-in behavior.
  • Consistent implementation between Vite (Node Buffer) and CF Workers (btoa) — appropriate for each runtime.
  • WWW-Authenticate header on 401 — proper RFC 7617 behavior, triggers browser credential prompt.
  • No protocol-level code touched.

Verdict: Request changes on items 1 and 2. The type error is a concrete build break; the timing comparison is a cheap fix on an auth boundary that should be done right. Items 3–4 are recommended but non-blocking.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@functions/_middleware.ts`:
- Line 28: Replace the direct `!==` comparison between `auth` and `expected` in
the middleware with a constant-time comparison to avoid timing attacks:
implement (or import) a `constantTimeCompare(a, b)` helper and call it where `if
(auth !== expected) return unauthorized()` currently is (i.e., use `if
(!constantTimeCompare(auth, expected)) return unauthorized()`), ensuring the
helper handles differing lengths and performs byte-by-byte constant-time checks
(Cloudflare Workers do not provide crypto.timingSafeEqual, so implement or
vendor a small constant-time routine).
- Line 27: The current computation of expected using
btoa(`${username}:${password}`) fails for non-ASCII characters; update the Basic
auth encoding to use a UTF-8 aware base64 encoder (e.g., replace the btoa usage
with a Buffer-based encoding or TextEncoder approach) so that expected is
computed as base64 of the UTF-8 bytes of `${username}:${password}` (ensure you
change the expression where expected is assigned and remove the btoa call,
referencing the existing variables username and password to produce the RFC
7617-compliant header).

In `@plugins/vite-plugin-basic-auth.ts`:
- Line 18: Replace the insecure direct comparison if (auth === expected) with a
constant-time comparison: hash both auth and expected (e.g., SHA-256) into
fixed-size buffers and use crypto.timingSafeEqual to compare the digests so
timing cannot reveal credential details; update the code around the
auth/expected check (the branch that currently uses if (auth === expected)) to
compute the digests and call timingSafeEqual, handling any crypto imports and
edge cases (ensure both inputs are converted to Buffers/strings before hashing).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ad34f9ca-14e6-4fa2-8016-6c3d02ff4897

📥 Commits

Reviewing files that changed from the base of the PR and between 1cfdb16 and 2ee081b.

📒 Files selected for processing (3)
  • functions/_middleware.ts
  • plugins/vite-plugin-basic-auth.ts
  • vite.config.ts

Comment thread functions/_middleware.ts Outdated
const auth = context.request.headers.get('Authorization')
if (!auth) return unauthorized()

const expected = 'Basic ' + btoa(`${username}:${password}`)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Critical: Encoding inconsistency with Vite plugin breaks non-ASCII passwords.

btoa() doesn't handle UTF-8 characters properly, while the Vite plugin uses Buffer.from() which correctly encodes UTF-8. This causes the dev server and production to compute different expected values for passwords containing non-ASCII characters (e.g., "café", "münchen"), breaking authentication inconsistently across environments.

Per RFC 7617, HTTP Basic Auth should support UTF-8.

🔧 Proposed fix using TextEncoder for UTF-8 support
-  const expected = 'Basic ' + btoa(`${username}:${password}`)
+  const credentials = `${username}:${password}`
+  const utf8Bytes = new TextEncoder().encode(credentials)
+  const binaryString = String.fromCharCode(...utf8Bytes)
+  const expected = 'Basic ' + btoa(binaryString)

Or, if non-ASCII passwords aren't required, document that only ASCII is supported and validate accordingly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const expected = 'Basic ' + btoa(`${username}:${password}`)
const credentials = `${username}:${password}`
const utf8Bytes = new TextEncoder().encode(credentials)
const binaryString = String.fromCharCode(...utf8Bytes)
const expected = 'Basic ' + btoa(binaryString)
🤖 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 `@functions/_middleware.ts` at line 27, The current computation of expected
using btoa(`${username}:${password}`) fails for non-ASCII characters; update the
Basic auth encoding to use a UTF-8 aware base64 encoder (e.g., replace the btoa
usage with a Buffer-based encoding or TextEncoder approach) so that expected is
computed as base64 of the UTF-8 bytes of `${username}:${password}` (ensure you
change the expression where expected is assigned and remove the btoa call,
referencing the existing variables username and password to produce the RFC
7617-compliant header).

Comment thread functions/_middleware.ts Outdated
Comment thread plugins/vite-plugin-basic-auth.ts Outdated
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 18, 2026

Deploying wallet-staging with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6acd835
Status: ✅  Deploy successful!
Preview URL: https://b506f4a6.wallet-staging-95g.pages.dev

View logs

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying tmp-boltz-upstream-mainnet-arkade-wallet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6acd835
Status: ✅  Deploy successful!
Preview URL: https://6def9145.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev
Branch Preview URL: https://basic-auth.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev

View logs

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying wallet-mutinynet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6acd835
Status: ✅  Deploy successful!
Preview URL: https://8a3f7fb7.arkade-wallet.pages.dev
Branch Preview URL: https://basic-auth.arkade-wallet.pages.dev

View logs

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying wallet-bitcoin with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6acd835
Status: ✅  Deploy successful!
Preview URL: https://6835c357.wallet-bitcoin.pages.dev
Branch Preview URL: https://basic-auth.wallet-bitcoin.pages.dev

View logs

Copy link
Copy Markdown

@arkanaai arkanaai Bot left a comment

Choose a reason for hiding this comment

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

Re-review — new commits address previous findings ✅

Both must-fix items from my prior review are resolved:

# Issue Resolution
1 PagesFunction unresolved type Replaced with local EventContext interface — no external type dep needed
2 Timing-unsafe === comparison crypto.subtle.timingSafeEqual (CF Workers) and node:crypto.timingSafeEqual (Vite) — both correct

Implementation looks clean:

  • functions/_middleware.ts: TextEncoder + crypto.subtle.timingSafeEqual with length pre-check. btoa available in CF Workers runtime. ✓
  • plugins/vite-plugin-basic-auth.ts: Buffer.from + timingSafeEqual with length pre-check. expected string captured in closure, re-buffered per request (acceptable). ✓
  • vite.config.ts: Plugin registered first in the array — middleware runs before other plugins. ✓
  • Both are no-ops when env vars are unset. ✓

Not protocol-critical — no VTXO, signing, or round-lifecycle code touched. This is deployment-layer auth gating on the SPA bundle.

Previous note on brute-force protection (item 3) still stands as a nice-to-have — recommend Cloudflare rate-limiting rules on the dashboard side rather than in-code.

LGTM. Approving.

@bordalix bordalix merged commit edfaf66 into master May 18, 2026
7 checks passed
@s373nZ s373nZ deleted the basic-auth branch May 18, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants