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:

Backend Description
LND Lightning Network Daemon (direct gRPC)
LNC Lightning Node Connect (remote LND via mailbox)
CLN Core Lightning
Eclair Eclair node
LNURL Lightning Network URL
NWC Nostr Wallet Connect
BOLT12 Reusable Lightning Offers

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

L402 module demo


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| M[Return 500 Internal Server Error]
    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, and Eclair.


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/dhananjaypurohit/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.