Lots of folks were curious how I connect Gummroad and Auth0 on my custom course platform so here's a short tutorial. The same approach works if you swap Gumroad out for Stripe ✌️
Here's the tl;dr:
- User visits your JAMStack app (Gatsby for me)
- User clicks Buy Button
- Gumroad checkout pops up
- User purchases
- Gumroad calls a webhook
- AWS Lambda wakes up, creates account on Auth0
- User is redirected back to JAMStack
- User can now login
You can replace the Gumroad popup with a redirect to Stripe Checkout. We use that approach in the example app for my ServerlessReact.Dev course.
If you want to support free trials, you can use the AWS Lambda to add a role for existing users instead of creating new accounts. That way people can login, use your app, and get extra permissions once they buy.
You can watch me figure this out from scratch on a stream:
Start with a buy button
Assuming you've got a JAMStack app – Gatsby, NextJS, or even CreateReactApp are all fine – a buy button is just a bit of React. I like to use Rebass buttons.
This renders a button as a link tag, links to Gumroad, and enables the Gumroad popover. Users can purchase without leaving the page and if that doesn't work (no JS, weird browser, etc), they go to Gumroad's checkout page.
You'll need to include Gumroad's script tag on your page. ReactHelmet works great for that.
AWS Lambda Webhook
The webhook is where things get interesting.
Gumroad supports a Gumroad Ping, which is a POST request sent to a URL of your choice on every purchase. Stripe calls it a Stripe Webhook.
Webhooks let you do stuff on important events in 3rd party services. Creating a user in our case.
I set my hook up using Serverless with AWS Lambda. NextJS's /api
directory would be a good choice too. Or Netlify's cloud functions. They're all the same thing – a JavaScript function that runs when a URL gets a POST request.
This config creates a new service, uses Node 12, adds some permissions, and creates a gumroadping
AWS Lambda function.
A benefit of using AWS directly is that you can use AWS Secrets Manager to securely store API keys and keep your infrastructure config in this one file.
sls deploy
spits out a URL. Gumroad sends a POST request and AWS runs your code.
pingHandler
pingHandler
is where that work happens.
A couple things happen here:
- Parse request body with
querystring
- Check product against a constant whitelist
- Create or update a user on Auth0 with
upsertUser
- Add authorization role to user
- Say all went well
We always return success and assume errors will throw. When your code throws AWS responds with a 500. That's fine.
We're also hardcoding the Student
role because Auth0 doesn't work with role names and it's too much work to read the list, find the ID, and add that.
Step 2 is important because Gumroad pings for all purchases. Wouldn't wanna give access to someone who bought a different product. 🙃
As you can see this code is very scalable and generic. But it doesn't have to be. That's the beauty of cloud functions – they do one thing and one thing only.
upsertUser
upsertUser
is where users get created or updated.
Using upserts lets you support free trials and people who repurchase after a refund or whatever. Folks who have an account already.
Get the Auth0 client, find user by email. If user exists, return, otherwise create a new user.
For better security we generate a random secure password. Users have to go through the password reset flow on their first login.
Makes the UX more cumbersome and the whole system more secure. You don't want to store these passwords and you don't want to send them by email. You also don't want them to be guessable.
Infosec matters.
getAuth0Client
getAuth0Client
is a helper method to instantiate an Auth0 client. Makes your code more readable :)
Call getAuth0Tokens
to get secrets, instantiate a new ManagementClient
for Auth0. This one lets you manage users and stuff.
auth0Tokens
auth0Tokens
is a helper method to read API tokens and secrets from AWS Secrets Manager. This is important to avoid hardcoding secrets in your code, sharing them with other developers, and making sure they're secure at rest.
You get a sort of triple-blind secret.
Public can't see it. Developers can't see it. Servers can't see it. Secret only exists in memory at runtime. 🔐
Attacking that would require an OS-level hack.
Reads secret from AWS Secrets Manager, stores it in local variable for next time so you don't have to ping ASM every time you need a secret while your code runs.
I should open source this 🤔
An important sidenote
You'll need 2 Auth0 apps. This one took me for a spin. 😅
1 app for your JAMStack frontend 1 app for your Lambda backend
Authenticate and Authorize users
You're creating users for every purchase. Now what?
Use useAuth to handle authentication and authorization in your app.
Assuming standard configuration from useAuth docs, you can paywall any component in your JAMStack app like this:
useAuth
handles the Auth0 authentication lifecycle and returns an isAuthenticated
method and a user
object.
Call isAuthenticated
to see if user is logged in with a valid session, use isAuthorized
to verify they've got the right role. Then let them through.
Otherwise show them the buy button.
Tell Auth0 to include role metadata
You'll have to add an Auth0 Rule that includes user roles in response data to your Auth0 config.
This was the smallest code that works for me. Cobbled together from online discussions, a few blogs, and some trial and error.
I didn't dive too much into details and I don't know why Auth0 doesn't include meta_data
by default.
Bonus UX points
For bonus UX points, you should give people temporary access when they come back from that Gumroad purchase.
Gumroad gives you specific URL params that mean "This user just bought your course". Would be great if they didn't have to then login, change their password, and go through a bazillion steps just to get access.
It's the approach I use on ServerlessHandbook.dev where there's no logins. Just local storage after a Gumroad redirect.
Just add a check ...
Make justBackFromGumroad
check the URL query :)
✌️
And that's how you can paywall parts of your JAMStack app.
To learn more about these techniques, check out ServerlessHandbook.Dev and my new course ServerlessReact.Dev
Cheers,
~Swizec
Continue reading about Connecting Gumroad to Auth0 for paywalled JAMStack apps
Semantically similar articles hand-picked by GPT-4
- Add granular role-based access to your JAMStack app
- How to set up Gatsby and Auth0 for easy authentication on your next project
- How serverless beats servers
- A JavaScript function that makes $40,000+/year
- What happens when you push AWS credentials to GitHub
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️