Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ngx_l402 — L402 Nginx Module

An L402 authentication module for Nginx that enables Lightning Network-based monetization for your REST APIs (HTTP/1 and HTTP/2).

It supports the following Lightning backends:

BackendDescription
LNDLightning Network Daemon (direct gRPC)
LNCLightning Node Connect (remote LND via mailbox)
CLNCore Lightning
EclairEclair node
LNURLLightning Network URL
NWCNostr Wallet Connect
BOLT12Reusable Lightning Offers

The module can be configured to charge per unique API call, enabling per-endpoint monetization based on request paths.


How It Works

graph TD;
    A[Request Received] --> B{Endpoint L402 Enabled?}
    B -->|No| C[Return 200 OK]
    B -->|Yes| D{"Any auth header present? (L402 or X-Cashu)"}
    D -->|No| F[Generate L402 Header macaroon & invoice]
    D -->|Yes| K["Parse L402 macaroon/preimage or X-Cashu (if present)"]
    F --> G{Header Generation Success?}
    G -->|No| I[Return 500 Internal Server Error]
    G -->|Yes| H[Add WWW-Authenticate Header]
    H --> J[Return 402 Payment Required]
    K --> L{Parse Success?}
    L -->|No| Q[Return 401 Unauthorized]
    L -->|Yes| AD{"Auto-detect enabled AND no preimage in header?"}
    AD -->|Yes| ND[Query Lightning node for settled invoice]
    ND --> NS{Invoice settled?}
    NS -->|No| NR[Return 402 Payment Required]
    NS -->|Yes| NV["Verify macaroon signature (preimage from node)"]
    NV -->|Valid| P[Return 200 OK]
    NV -->|Invalid| Q[Return 401 Unauthorized]
    AD -->|No / preimage provided| N["Verify macaroon/preimage OR Cashu proofs (whitelist; P2PK lock if enabled; double-spend check; amount >= price)"]
    N --> O{Verification Success?}
    O -->|No| Q
    O -->|Yes| P

Auto-detect: When l402_auto_detect_payment on is set and the client sends only Authorization: L402 <macaroon> (no preimage), the server queries the Lightning node directly. Supported on LND, CLN, BOLT12, Eclair, and NWC wallets that implement lookup_invoice — see the support matrix.

Response Codes

StatusWhen
200Payment verified — the upstream response is returned
402No credential presented, or auto-detect found the invoice unpaid. Carries the WWW-Authenticate L402 challenge, and X-Cashu when Cashu is enabled
401A credential was presented and failed: malformed, tampered, replayed, or the preimage does not match. Carries WWW-Authenticate: L402; retry without a credential for a fresh challenge
400A Cashu token from an unlisted mint, in the wrong unit, or below the price
429Invoice rate limit hit (l402_invoice_rate_limit)
500The gateway failed — an unreachable mint, Lightning node or Redis, or a failed database write, not a problem with your payment
503A Lightning credential arrived while REDIS_URL is set but Redis is unreachable; retry once it is back

402 only asks for payment: the initial challenge, or an auto-detect invoice not paid yet. A credential that fails is 401, never 402the L402 specification requires this so clients can tell “you need to pay” from “your credential is broken”. The 400 cases are the ones NUT-24 names.

A 500 on a request that carried a Cashu token leaves the token’s fate unknown: swapping it at the mint and recording the proofs are separate steps, so a failure between them may have spent the token or not touched it. Treat it as an outage rather than a rejected payment, and don’t discard the token. Other 500s — a missing price, an uninitialised module — are unrelated to payment.


Quick Start

Note: This module requires NGINX version 1.28.0 or later.

The fastest way to get started is with Docker:

docker run -d \
  --name l402-nginx \
  -p 8000:8000 \
  -e LN_CLIENT_TYPE=LNURL \
  -e LNURL_ADDRESS=username@your-lnurl-server.com \
  -e ROOT_KEY=your-32-byte-hex-key \
  ghcr.io/ngx-l402/ngx-l402:latest

Then test it:

# Should return 200 OK
curl http://localhost:8000/

# Should return 402 Payment Required with L402 header
curl -i http://localhost:8000/protected

See the Installation section for full setup options.