{"id":15120211,"url":"https://github.com/tierion/boltwall","last_synced_at":"2026-01-16T22:35:10.505Z","repository":{"id":47738455,"uuid":"201133921","full_name":"Tierion/boltwall","owner":"Tierion","description":"Bitcoin Lightning paywall and authentication using LSATs. Built with LND, Nodejs, and Typescript.","archived":false,"fork":false,"pushed_at":"2023-04-26T19:00:52.000Z","size":12754,"stargazers_count":109,"open_issues_count":4,"forks_count":18,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-28T05:55:52.663Z","etag":null,"topics":["bitcoin","lightning-node","macaroons","paywall","typescript"],"latest_commit_sha":null,"homepage":"https://tierion.github.io/boltwall/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tierion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-07T21:59:57.000Z","updated_at":"2024-06-19T02:54:29.174Z","dependencies_parsed_at":"2024-06-19T02:54:06.254Z","dependency_job_id":"9f2065f7-8355-4453-8f82-afb0d3b9f3c4","html_url":"https://github.com/Tierion/boltwall","commit_stats":null,"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tierion%2Fboltwall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tierion%2Fboltwall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tierion%2Fboltwall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tierion%2Fboltwall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tierion","download_url":"https://codeload.github.com/Tierion/boltwall/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234485103,"owners_count":18840756,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitcoin","lightning-node","macaroons","paywall","typescript"],"created_at":"2024-09-26T02:00:38.102Z","updated_at":"2025-09-28T04:30:40.790Z","avatar_url":"https://github.com/Tierion.png","language":"TypeScript","funding_links":[],"categories":["Tools"],"sub_categories":[],"readme":"[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n[![Build Status](https://travis-ci.com/Tierion/boltwall.svg?branch=master)](https://travis-ci.com/Tierion/boltwall)\n[![Coverage Status](https://coveralls.io/repos/github/Tierion/boltwall/badge.svg?branch=ci)](https://coveralls.io/github/Tierion/boltwall?branch=ci)\n\n# ⚡️ Boltwall ⚡️\n\nBitcoin Lightning paywall and authentication using LSATs. Charge to access your API without requiring user accounts, API keys, credit cards, or storing any user data. All you need is a lightning node and a single line of code in your server. Built with [LND](https://lightning.engineering/), Nodejs, and Typescript.\n\nAll you need to put a paywall in front of a route on your server is this one line of code:\n\n```js\napp.use(boltwall())\n```\n\n- [⚡️ Boltwall ⚡️](#%e2%9a%a1%ef%b8%8f-boltwall-%e2%9a%a1%ef%b8%8f)\n    - [Supported Features](#supported-features)\n  - [System Requirements](#system-requirements)\n  - [Usage](#usage)\n  - [Test the API](#test-the-api)\n  - [Required Environment Variables](#required-environment-variables)\n    - [Lightning Configs](#lightning-configs)\n  - [What is an LSAT](#what-is-an-lsat)\n    - [Authentication Flow](#authentication-flow)\n    - [Custom Authorization w/ Macaroons](#custom-authorization-w-macaroons)\n    - [Pre-built Configs](#pre-built-configs)\n      - [**`TIME_CAVEAT_CONFIGS`**](#time_caveat_configs)\n      - [**`ORIGIN_CAVEAT_CONFIGS`**](#origin_caveat_configs)\n      - [**`ROUTE_CAVEAT_CONFIGS`**](#route_caveat_configs)\n  - [HODL Invoices](#hodl-invoices)\n    - [Example Implementation and Access Flow](#example-implementation-and-access-flow)\n    - [Generation](#generation)\n    - [Authorization Flows](#authorization-flows)\n    - [Making the Payment](#making-the-payment)\n    - [A `held` Invoice is a Paid Invoice](#a-held-invoice-is-a-paid-invoice)\n  - [3rd Party Authentication](#3rd-party-authentication)\n    - [Usage](#usage-1)\n      - [Authentication flow](#authentication-flow-1)\n  - [Documentation](#documentation)\n    - [Custom Configs \u0026 Caveats](#custom-configs--caveats)\n    - [REST API](#rest-api)\n    - [Full API Documentation](#full-api-documentation)\n\n### Supported Features\n\n- New LSAT protocol for authentication\n- Protect routes in your own API by using as a middleware\n- Custom attenuation via macaroons\n- Optional configurations available for time and IP restricted access\n- [HODL Invoices](#hodl-invoices)\n- oAuth-like authorization for compatible 3rd party services (Coming soon)\n\n## System Requirements\n\n- Node \u003e 11.10.0\n- npm \u003e 6.9.0\n\nYour project must also use `Expressjs` 4.x as well as the `cors` and `body-parser` middleware.\nRestify is also supported although not broadly tested.\n\n## Usage\n\nTo use as a middleware in an existing server, just install from npm into your project,\nand use before any routes that you want protected.\n\n\u003e **NOTE:** Order matters with middleware. Any routes that appear _after_ boltwall will require\n\u003e proper authentication in order to access. Boltwall can be used within routes to keep it isolated\n\u003e from other routes you want to remain free.\n\nAn example project can be seen in `src/server.ts`, which can be run with `yarn start`\n(after [configuration](#required-environment-variables)).\n\nA very simple server file, with no special configurations, could look like this:\n\n```javascript\nconst express = require('express')\nconst cors = require('cors')\nconst bodyParser = require('body-parser')\n\nconst { boltwall } = require('boltwall')\n\nconst app = express()\n\n// middleware\napp.use(cors())\n// parse application/x-www-form-urlencoded\napp.use(bodyParser.urlencoded({ extended: false }))\n// parse application/json\napp.use(bodyParser.json())\n\napp.get('/', (_req, res) =\u003e {\n  return res.json({\n    message: 'Home route comes before boltwall and so is unprotected.',\n  })\n})\n\napp.use(boltwall())\n\n// this will require payment and proper lsat to access\napp.get('/protected', (_req, res) =\u003e\n  res.json({\n    message:\n      'Protected route! This message will only be returned if an invoice has been paid',\n  })\n)\n\napp.listen(5000, () =\u003e console.log('listening on port 5000!'))\n```\n\n## Test the API\n\n**Running the example server**\n\nTo run the test server, clone the repo, add appropriate [configs](#required-environment-variables)\nto a local `.env` file, and from the directory run:\n\n```bash\n$ yarn install\n$ yarn start\n```\n\nThis runs the server located in `/src/server.ts`, which you can edit to test the middleware's\nbehavior.\n\nOnce the server is running, you can test the API:\n\n1. `GET http://localhost:5000/node` to get connection information about your lightning node\n   (no payment required).\n\n2. `GET http://localhost:5000/protected?amount=[amount]` will return a `402` error for payment required. An LSAT challenge\n   will be available in the returned `WWW-Authenticate` header. Decode LSAT to get full invoice information. Amount in query string will be used in invoice generation unless below\n   minAmount configured in boltwall. If no amount is set, then minAmount will be used.\n\n3. `GET http://localhost:5000/protected` with appropriate LSAT in Authorization header (including\n   preimage) will return the response from the protected route\n\n4. `POST http://localhost:5000/invoice` with the following JSON body to get a new invoice (there\n   is no relation to any lsat and so cannot be used for authentication): `{ \"amount\": 30 }`\n\n5. `GET http://localhost:5000/invoice?id=[payment hash]` returns information for invoice with given\n   payment hash including payment status and payreq.\n\nRead more about the REST API in the [documentation](#documentation).\n\n## Required Environment Variables\n\nSeveral environment variables are required when running `boltwall`.\nThese serve the purpose of connecting to your lightning node and managing/signing macaroons\nfor authentication/authorization.\n\n### Lightning Configs\n\n**Lightning configs (either lnd connection info _or_ OpenNode API key depending on connection type)\nare required environment variables**\n\nIf you are connecting to a lightning node you will need the following in your project's `.env` file\nor on the `process.env` object\n\nLearn how to find these values for your node\n[in this article](https://medium.com/@wbobeirne/making-a-lightning-web-app-part-1-4a13c82f3f78)\nby Will O'Beirne. You can also try this tool by [lightning joule](https://lightningjoule.com/tools/node-info).\n\n```\nLND_TLS_CERT=[BASE64 or HEX encoded cert here]\nLND_MACAROON=[BASE64 or HEX encoded cert here]\nLND_SOCKET=[address of node here, e.g. localhost:10006]\n```\n\nAlternatively, if you are using OpenNode for managing payments,\n[create an OpenNode account](https://dev.opennode.co) (currently testnet only),\ngenerate an API key and save it as:\n\n```\nOPEN_NODE_KEY=[API KEY HERE]\n```\n\nIf you have both the lnd configs and OpenNode, _lnd will take precedence_.\n\nA `SESSION_SECRET` can also be set but will be generated with a secure number of random bytes if\nnone is provided.\n\n```\nSESSION_SECRET=[RANDOM STRING MINIMUM 32 BYTES IN LENGTH]\n```\n\nIf you don't set this yourself, then the secret is not persisted between server restarts. This means\nthat LSATs generated before the restart are no longer valid _after_ restart since the signing key\nused to generate (and validate) macaroons will have changed.\n\n## What is an LSAT\n\nLSATs are a new authentication scheme first introduced by Lightning Labs CTO Olaoluwa Osuntokun. Slides from\nthe original presentation can be found [here](https://docs.google.com/presentation/d/1QSm8tQs35-ZGf7a7a2pvFlSduH3mzvMgQaf-06Jjaow/edit#slide=id.p).\n\nThe idea is to create a standardized specification format for dealing with _payment-based_ authentication,\nin contrast to the username/password (a.k.a. \"Basic Authentication\") and token based (most commonly used in\nOAuth constructions) authentication schemes in common use today. By combining a\ncryptographically verifiable proof of payment from a lightning invoice with its corresponding\npreimage and a [macaroon](http://hackingdistributed.com/2014/05/16/macaroons-are-better-than-cookies/),\nthe idea is that a new, flexible, and private authorization protocol can be developed.\n\nCheckout `lsat-js` for a separate utility library available for manipulating, interacting\nwith, and validating LSATs. Available on npm: https://www.npmjs.com/package/lsat-js\n\n### Authentication Flow\n\nThere are three main stages to the authentication flow with LSATS:\n\n1. When a request is made to protected route, a `402 Payment Required` response is sent back.\n   This includes a `WWW-Authenticate` header with an LSAT. This is an encoded \"challenge\"\n   that includes a macaroon (read more below to learn how these work) and an invoice value.\n\n1. The consumer of the API extracts and pays the invoice from the LSAT. After payment, a payment preimage\n   should be revealed that acts as a cryptographically verifiable proof of payment.\n\n1. The consumer can now compose their LSAT using the preimage and the macaroon from the original challenge\n   and put it in the `Authorization` http header like so: `LSAT [macaroon]:[preimage]`\n\nSince the payment hash associated with the paid invoice could _only_ have been generated using the preimage\n(also known as a \"secret\") and that preimage would be impossible to guess and so could only have been retrieved\nafter paying the invoice, this serves as proof of payment and the server can verify that the request is authorized.\n\n### Custom Authorization w/ Macaroons\n\nBoltwall allows for flexible authorization schemes. Effectively, this means that a server\nthat is implementing Boltwall to protect content can dictate factors such as how long\nauthorization is valid for based off of a payment or restrict access to only the originating IP.\n\nAs an example, the configuration in the example file `src/server.ts`, sets up authorization that\nis valid for 1 second for every satoshi paid in the invoice.\nSo if a user pays a 30 satoshi invoice, then access is allowed for 30 seconds.\n\nThe config object should be passed to `boltwall` on initialization. e.g. `app.use(boltwall(myConfig))`, where `myConfig` provides the relevant properties. Currently, the config supports\nfour properties: `getCaveats`(func), `caveatSatisfiers` (func), `getInvoiceDescription`, and `minAmount`.\n\nMore information on the configs can be found in the\n[API Documentation](https://Tierion.github.io/boltwall/interfaces/_src_typings_configs_d_.boltwallconfig.html).\n\n### Pre-built Configs\n\nBoltwall exposes some default configs you can use in your own server. Simply import\nthem from the module and then pass them into boltwall when `use`ing it in your express\nserver.\n\n```javascript\nimport { boltwall, TIME_CAVEAT_CONFIGS } from 'boltwall'\n\n// ...  rest of your server code\n\napp.use(boltwall(TIME_CAVEAT_CONFIGS))\n\n// ... protected routes and any other server code\n```\n\nSince `getCaveats` and `caveatSatisfiers` can also accept an array of functions,\nyou can also combine configs to add multiple caveats and their corresponding satisfiers.\n\nCurrently Boltwall provides the following configs:\n\n#### **`TIME_CAVEAT_CONFIGS`**\n\nThis creates a restriction that any authorization is only valid for a number of seconds\nequal to the number of satoshis paid.\n\nThere is also support for a custom rate expressed in satoshis/second that can be added to the boltwall\nconfig object. The expiration time will be calculated according to this rate and the number of\nsatoshis required for payment in the invoice.\n\nFor example, if the rate is .01 satoshis per second, and a 10,000 satoshi invoice requires payment\nto validate the LSAT, then a caveat will be attached that expires in 1,000,000 seconds (10000/.01)\nor approximately 11.5 days.\n\nTo get the above result, simply initialize boltwall like this:\n\n```javascript\napp.use(boltwall({ ...TIME_CAVEAT_CONFIGS, rate: 0.01 }))\n```\n\n#### **`ORIGIN_CAVEAT_CONFIGS`**\n\nThis creates a restriction that any authorization is only valid from the IP that originally\nmade the request for access.\n\n#### **`ROUTE_CAVEAT_CONFIGS`**\n\nThis creates a restriction that any authorization is only valid for the route that originally\nwas requested to access. There is an option to add a master route to your config to create an LSAT that works to access all routes. Another option is to allow sub-routes, meaning an LSAT to access \"/protected\" will also grant access to \"/protected/images\"\n\n```javascript\napp.use(boltwall({ ...ROUTE_CAVEAT_CONFIGS, masterRoute: '/master', allowSubroutes: true }))\n```\n\n\n## HODL Invoices\n\nHODL invoices are a unique payment construction in lightning that allow a payee\nto simulate escrow-type situations or fidelity bonds in a lightning payment.\n\nIn a nutshell, a HODL invoice allows you to create a payment that does not\nautomatically settle, but instead is \"held\" until someone (either the owner of the node\nor, more likely, some other party that is prepared to release the payment based\non some conditions) reveals the preimage that the invoice is locked to. If\nthis secret is never revealed, the `held` payment is eventually refunded back to the\noriginal payer.\nYou can read more about how they are constructed and examples of potential use-cases\n[here](https://github.com/lightningnetwork/lnd/pull/2022).\n\n**NOTE:** Your lightning node MUST have the `invoicesrpc` flag enabled in order\nto support hodl invoices.\n\nBoltwall includes basic support for creating and settling hodl invoices (cancelling\nmust be done directly by the owner of the node and is not exposed via the Boltwall\nAPI at this time to avoid exposing potential [double-spend](https://en.wikipedia.org/wiki/Double-spending)-like risks).\n\n### Example Implementation and Access Flow\n\nTo enable a paywall that uses hodl invoices instead of normal invoices, simply initialize\nthe middleware with `hodl` set to true in the config:\n\n```js\napp.use((req, res, next) =\u003e {\n  if (req.path === 'protected' \u0026\u0026 !req.body.paymentHash) {\n    // Note: you'll probably want to save the secret somehow\n    // otherwise the hodl invoice can't be redeemed\n    const secret = crypto.randomBytes(32)\n    const paymentHash = crypto\n        .createHash('sha256')\n        .update(secret)\n        .digest()\n    req.body.paymentHash = paymentHash\n  }\n  next()\n})\napp.use(boltwall({ hodl: true }))\n// all routes after this will require payment to a hodl invoice\napp.get('/protected', (req, res) =\u003e res.send('This route is protected'))\n```\n\n1. The initial request for the route _requires_ a paymentHash in the request body. This is\n   how a hodl invoice is created. The payment hash can either be provided by the client\n   or added in a middleware before `boltwall` is initialized (as in the example above).\n2. Boltwall will return an LSAT challenge in the `WWW-Authenticate` header as normal\n3. The client should pay the invoice.\n4. Since this is a hodl invoice, the client won't get a `preimage` until the invoice settles.\n   How this is managed is up to the implementor and the architecture of the application. If the\n   server is storing the secret, or retrieving it by some other means (such as with split payments),\n   it can add it to the LSAT when it wants to invalidate _future_ requests.\n5. Once the invoice settles and has a status of `paid` (instead of `held`) the LSAT is considered\n   expired and future requests will be `Unauthorized`\n\n### Generation\n\nThe source of the pre-image and payment hash can be whatever you want. One common\nconstruction is for the pair to be tied to another invoice, which makes it so that the HODL\ninvoice can't settle until another invoice settles and reveals its own preimage.\n\n### Authorization Flows\n\nAll authorization mechanisms (i.e. via macaroons) are preserved when using HODL invoices.\nThe root macaroon is created and added to the LSAT when creating the invoice as normal.\nIf time caveats are enabled, then this will timeout based on the amount paid. Custom\nconfigurations can be devised and passed in to boltwall upon initialization.\n\n### Making the Payment\n\nWhen making the payment with your lightning client, it may look like the payment\nis stuck or is hanging. This is normal and is the result of a client having no way\nto know whether an invoice is normal or HODL so it is waiting for the invoice to settle.\nThis won't happen for a HODL invoice until you settle it with the preimage.\n\n### A `held` Invoice is a Paid Invoice\n\nWhat this means is that the paywall considers the invoice paid and \"unlocks\"\nthe protected content, by providing the discharge macaroon even though your node\ntechnically may not have settled the payment yet and so doesn't have access to the funds.\n\nBoltwall's default behavior for handling HODL LSAT requests is to settle an invoice when\nthe secret is provided in the LSAT _after_ the request has been authorized. This means\nthat a request with the secret will be the _last_ request for that LSAT since afterwards\nit will be `paid` and therefore \"expired\".\n\n## 3rd Party Authentication\n\n### Usage\n\nTo enable, simply set `oauth` to true when initializing middleware:\n\n```javascript\nimport { boltwall } from 'boltwall'\n\n// ...  rest of your server code\n\napp.use(boltwall({ oauth: true }))\n\n// ... protected routes and any other server code\n```\n\nThis will add a requirement for requests to protected routes that an `auth_uri` be indicated\nin the request query. This indicates the 3rd party server that will process and confirm payments,\nultimately signing a \"challenge\" to enable the holder of the corresponding LSAT access to the protected route.\n\nBoth the server processing requests for protected routes and the authorizing server signing the challenge\nmust have `oauth` enabled.\n\n**NOTE:**\nBoltwall's upgrade to support LSATs _removed_ previous support for 3rd party caveats\nto enable OAuth-like constructions. A coordination step around a shared key was used to verify\n3rd party caveats and corresponding discharge macaroons. Since Boltwall v5, a new protocol\nis used that no longer requires any coordination to support 3rd party authentication.\n\nThe use of macaroons for authorization allows for a lot of flexibility. Aside from the customization laid out\nin the section above covering the configurations, `boltwall`'s API also enables authorization schemes\nwith 3rd parties or as a 3rd party itself.\n\n**Think of it like running your own oAuth service.**\n\nIn the same way that Google's oAuth allows a 3rd party service to sign you in to their platform by verifying\nyour Google account, with Boltwall, your API can act like Google, where instead of verifying your account, the\nservice verifies payment. An example of how this can be implemented is in the [Prism Reader](https://prismreader.app) app.\nPrism Reader hosts documents provided by users. Authors of content can optionally require payment to view that content. Rather\nthan Prism acting as a custodian for the funds and issuing payouts, an author can run a boltwall instance, give Prism\nthe url of your API, and users will then **only be able to read your content once _your\nserver_ has acknowledged payment**!\n\n#### Authentication flow\n\nThe below image should give an idea of the authentication flow between the boltwall api, a lightning node,\na 3rd party app requiring authorization, and the client paying for access.\n![boltwal architecture diagram](https://raw.githubusercontent.com/Tierion/boltwall/master/boltwall-diagram.png 'diagram')\n\n## Documentation\n\n### Custom Configs \u0026 Caveats\n\nBoltwall supports custom configurations that can be set on initialization.\nOne important part of this is the ability to create custom macaroon caveats and the satisfiers\nyour server will use to evaluate their validity. The `TIME` and `ORIGIN` configs described above\nare just two examples of these. Note that each caveat must have a corresponding satisfier\nin order for a macaroon to validate.\n\nThe properties that can be passed (none are required) to the boltwall config object are:\n\n- `getCaveats`: function or array of functions to generate caveats attached to LSAT macaroons\n- `caveatSatisfiers`- (required if getCaveats is set) Satisfier object or array of Satisfiers\n  (see full documentation for more details on writing your own satisfiers) for evaluating\n  caveats on a macaroon.\n- `getInvoiceDescription` - an optional function that returns a string to be used in the invoice description\n- `minAmount` - minimum amount to create invoices with if none is passed in request body\n- `hodl`- (optional, false by default) boolean, true to enable a hodl paywall.\n- `oauth`- (optional, false by default) boolean, true to enable 3rd party authentication.\n- `rate` - (optional, undefined by default) float, a rate to be used by other caveatGetters.\n  For example, the TIME_CAVEAT_CONFIGS applies this as a satoshis/second value to calculate expiration.\n\nMore indepth documentation for these properties can be found in the [docs](https://Tierion.github.io/boltwall/interfaces/_src_typings_configs_d_.boltwallconfig.html)\n\n### REST API\n\nCheck out the Swagger Docs for detailed API information. This details what to expect\nat the various routes provided for by `Boltwall`.\n\n**[REST API](https://app.swaggerhub.com/apis-docs/boltwall/boltwall/2.0.0-beta-oas3)**\n\n### Full API Documentation\n\nAPI documentation, with details on the code, API, and Typescript definitions\ncan be found at the [documentation website](https://Tierion.github.io/boltwall/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftierion%2Fboltwall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftierion%2Fboltwall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftierion%2Fboltwall/lists"}