Skip to content

ServerlessReact.dev

Student Login
  • Welcome to the workshop
The workshop
Before you head out

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

  1. Install stripe
yarn add stripe
  1. Create a server-side prop for payment intent client secret
const paymentIntent = await stripe.paymentIntents.create({
amount: 1099,
currency: "usd",
})
clientSecret: paymentIntent.client_secret
  1. Install stripe client libs
yarn add @stripe/react-stripe-js @stripe/stripe-js
  1. Render basic Stripe form
const stripePromise = loadStripe("pk_5WyhDiasKtEhmWiYGeGLvHRqm5Fcn")
const elems = () => (
<Elements stripe={stripePromise}>
<CardElement />
</Elements>
)
  1. Submit payment to Stripe
// needs to be in a component inside <Elements> context
const 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.

  1. Create an endpoint
export default function handler(req, res) {
if (req.method === "POST") {
// Process a POST request
}
}
  1. Hook up local stripe testing
stripe listen --forward-to http://localhost:3000/api/stripe-hook
stripe trigger payment_intent.succeeded
  1. Process stripe events
const stripe = Stripe("kvBqgq7OCZs9e730tl9nEbG1I2JDfjWo")
// printed by stripe console, use Dashboard key in production
const endpointSecret = "whsec_uqRFAm4Mjcsj8VZzLsa1k4v8itMtW6HG"
const sig = req.headers["stripe-signature"]
let event
try {
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 })
  1. 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 production
async 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],
}
);

Did you enjoy this chapter?

Previous:
Add authentication
Next:
How was it?
Created bySwizecwith ❤️