Monetization
Now that users can authenticate, it's time to add a payment button. We'll use Stripe and hook up a /api route to add a role to users.
We're loosely following Stripe's instructions: https://stripe.com/docs/payments/accept-a-payment?integration=elements
- Install stripe
yarn add stripe
- Create a server-side prop for payment intent client secret
const paymentIntent = await stripe.paymentIntents.create({amount: 1099,currency: "usd",})clientSecret: paymentIntent.client_secret
- Install stripe client libs
yarn add @stripe/react-stripe-js @stripe/stripe-js
- Render basic Stripe form
const stripePromise = loadStripe("pk_5WyhDiasKtEhmWiYGeGLvHRqm5Fcn")const elems = () => (<Elements stripe={stripePromise}><CardElement /></Elements>)
- Submit payment to Stripe
// needs to be in a component inside <Elements> contextconst stripe = useStripe()const elements = useElements()
const result = await stripe.confirmCardPayment("{CLIENT_SECRET}", {payment_method: {card: elements.getElement(CardElement),billing_details: {name: "Jenny Rosen",},},})if (result.error) {// Show error to your customer (e.g., insufficient funds)console.log(result.error.message)} else {// The payment has been processed!if (result.paymentIntent.status === "succeeded") {// Show a success message to your customer// There's a risk of the customer closing the window before callback// execution. Set up a webhook or plugin to listen for the// payment_intent.succeeded event that handles any business critical// post-payment actions.}}
5. Add a webhook to authorize paying users
Webhooks are tiny APIs used for glue-code between services. Ours will receive payment info from Stripe and add a role to Auth0. We'll then be able to check users have that role before giving them access.
We're following Stripe Docs: https://stripe.com/docs/payments/handling-payment-events#create-webhook
All this happens in a /api route that will serve as our webhook.
- Create an endpoint
export default function handler(req, res) {if (req.method === "POST") {// Process a POST request}}
- Hook up local stripe testing
stripe listen --forward-to http://localhost:3000/api/stripe-hookstripe trigger payment_intent.succeeded
- Process stripe events
const stripe = Stripe("kvBqgq7OCZs9e730tl9nEbG1I2JDfjWo")// printed by stripe console, use Dashboard key in productionconst endpointSecret = "whsec_uqRFAm4Mjcsj8VZzLsa1k4v8itMtW6HG"const sig = req.headers["stripe-signature"]let eventtry {event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret)} catch (err) {response.status(400).send(`Webhook Error: ${err.message}`)}console.log(event)res.json({ received: true })
- Add user role on Auth0
Modeled after: https://github.com/Swizec/gumroad-webhook/blob/master/src/gumroadPing.ts
import { ManagementClient } from "auth0";// All secrets should go into ENV vars for productionasync function getAuth0Client() {const auth0 = new ManagementClient({domain: `${secrets.domain}.auth0.com`,clientId: secrets.clientId,clientSecret: secrets.clientSecret,scope: "read:users update:users create:users",});return auth0;}const users = await auth0.getUsersByEmail(purchaseData.email);await auth0.assignRolestoUser({ id: users[0].user_id! },{roles: [roleId],});