Making a Lightning Web App: Part 4

Integrating WebLN for payments and message signatures

William O'Beirne
5 min readJun 12, 2019


Hey, this is part 4 of a 5 part series on building a Lightning app. If you’re just interested in learning more about WebLN, it’s easy to follow along! But if you want to start from the beginning, you can check out part 1 here.

Our humble pay-to-post Lightning app from part 3 works pretty well at this point, but we can do a bit more to leverage functionality our node offers by integrating WebLN, and using its API for node interactions.

WebLN is a standard for browsers to facilitate communication between user’s Lightning nodes and web apps that want to use them. You can read more about it in the official documentation, but the gist of it is that it reduces friction for users to make payments, generate invoices, or sign and verify messages if they have a browser or extension that is compatible.

Today we’re going to change our payment flow to use WebLN, and we’ll add support for signing your post before you make it, and verifying signatures of other posts. Let’s get started!

Getting Started: Clone the (new) Project

Yet again, we’ll start with cloning and checking out this part’s tutorial branch.

# Run this if you don't already have the repository
git clone
cd lightning-app-tutorial
git checkout part-4
# Run this inside the repository directory if you already had it
git fetch origin
git checkout part-4

And we’ve added two new dependencies for WebLN that we’ll talk about in a bit, so go ahead and install those too.

npm install

Now that that’s out of the way, let’s look at the changes.

WebLN Payments

Adding WebLN payments to your application is an easy change, and has the benefit of allowing us to get rid of a bunch of UI code as well. The process of presenting the user with an invoice, and waiting for them to pay can be entirely replaced with this form submission handler:

Don’t worry about that new `signature` state variable, we’ll cover it shortly.

We no longer need to set the payment request in state, since we’re no longer rendering it. The user’s WebLN client will do the job of informing the user of the payment and having them confirm or deny it. If their client allows for auto-payments, they may not even see anything at all! All we need to do is disable the button and show a spinner while isPosting is true, and render an error if one occurs.

Signatures and Verifications

Sitting beside the submit post button is a new “Sign message” button. Clicking on this will give the user the opportunity to sign their message with their node’s private key, so that you can prove it was posted by the owner of that node. Hot takes will never be the same with this level of verification.

Let’s check out the changes, in PostForm, Posts, and the POST /api/posts endpoint that make this possible, starting with PostForm:

We trigger signMessage when the button beside the submit button is clicked, which will prompt the user to sign the current state of their content field using their node via WebLN. If the content field is changed, we wipe out the signature, since it’s no longer valid. When they submit the form, we now send the signature along with the content for verification.

Let’s take a look at that endpoint in server/index.tsx:

Now we’re pulling an optional signature argument out of the request body. If it’s provided, we verify it using our server’s node, checking the signature against the post content they sent. If our node says the signature is invalid, we’ll reject their request. Otherwise, we’ll include it with the rest of the post’s data.

Now when we get posts back from the server, they may include a post.signature field. We can use this to conditionally add a verify button to our posts in the Posts component if it has one, and trigger this when clicked:

Here we can just call webln.verifyMessage with the post signature and content. We don’t need to do anything on our end with this call, as it’s up to the user’s WebLN client to display to the user whether or not the signature is valid. This makes it impossible for someone to maliciously fake a signature, since the user verifies outside of our app.

This is what it all looks like for a user verifying a post with their node in Joule:

Providing a WebLN Fallback

Not every browser has a WebLN provider, which would cause those requestProvider calls to fail out. Fortunately, there’s a fallback UI library that will handle those users called react-webln-fallback. It comes in a few different varieties to easily work with whatever UI library you’re using. Since we’re using reactstrap for our Bootstrap components, we can use react-webln-fallback-reactstrap.

First, we include the fallback component somewhere high up in our render tree, for example in our root App component:

This will add its own WebLN provider if it doesn’t detect one, and will pop up React components whenever we call WebLN methods in the previous components.

We also need one change in PostForm to inform the WebLN fallback when a payment is completed. The fallback components aren’t actually hooked up to a node, so it needs some manual intervention to know when payments go through. Back in PostForm, we’ll just add one line to where our pendingPost is checked against new posts that come in from props. When one of those comes in, we’ll call the paymentComplete method provided by the fallback library:

So now user’s without a WebLN client will see this instead:

There are also fallbacks available for antd, react-bootstrap, semantic-ui, and material-ui!

Final Thoughts

While our simple app probably would have been fine with its previous payment flow, WebLN opens us up to a more micro-payment driven experience. Users can be prompted to make payments on the fly, and if their client is capable of it, may make payments automatically in the background.

By implementing WebLN now, we cater to a wider range of potential clients and use cases that are more difficult with the traditional way of interacting with users’ nodes.

For the next and final part of this tutorial series, we’ll be looking at launching our application to a production server so that you can share it around with your friends, and start earning your first few sats. Stay tuned for that!