Skip to content

Commit

Permalink
feat: Stripe webhook signing secret (#21)
Browse files Browse the repository at this point in the history
* refactor: Add stripe-client

* feat: Add middleware to handle Stripe webhook signing
  • Loading branch information
Jonathan Steele authored Mar 18, 2021
1 parent 8b3ba42 commit a75467e
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 12 deletions.
3 changes: 2 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ GRAPHCMS_MUTATION_TOKEN=
NEXT_PUBLIC_GRAPHCMS_TOKEN=
NEXT_PUBLIC_GRAPHCMS_URL=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
STRIPE_SECRET_KEY=
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SIGNING_SECRET=
4 changes: 1 addition & 3 deletions lib/create-order.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import graphcmsMutationClient, { gql } from '@/lib/graphcms-mutation-client'
import Stripe from 'stripe'
import stripe from '@/lib/stripe-client'

export const createOrderMutation = gql`
mutation CreateOrderMutation($order: OrderCreateInput!) {
Expand All @@ -9,8 +9,6 @@ export const createOrderMutation = gql`
}
`

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY)

async function createOrder({ sessionId }) {
const {
customer,
Expand Down
3 changes: 3 additions & 0 deletions lib/stripe-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Stripe from 'stripe'

export default new Stripe(process.env.STRIPE_SECRET_KEY)
25 changes: 25 additions & 0 deletions lib/stripe-signing-secret.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import stripe from '@/lib/stripe-client'

const stripeSigningSecret = (handler) => async (req, res) => {
const chunks = []

for await (const chunk of req) {
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk)
}

let event

try {
event = stripe.webhooks.constructEvent(
Buffer.concat(chunks),
req.headers['stripe-signature'],
process.env.STRIPE_WEBHOOK_SIGNING_SECRET
)
} catch (err) {
return res.status(400).json({ message: err.message })
}

return handler(req, res, event)
}

export default stripeSigningSecret
4 changes: 1 addition & 3 deletions pages/api/stripe/create-checkout-session.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import Stripe from 'stripe'

import graphcmsClient, { gql } from '@/lib/graphcms-client'
import stripe from '@/lib/stripe-client'

export default async (req, res) => {
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY)
try {
const { currency, items, locale, success_url, ...rest } = req.body

Expand Down
19 changes: 14 additions & 5 deletions pages/api/stripe/webhook.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import createOrder from '@/lib/create-order'
import stripeSigningSecret from '@/lib/stripe-signing-secret'

export default async (req, res) => {
export const config = {
api: {
bodyParser: false
}
}

const handler = async (req, res, event) => {
const permittedEvents = ['checkout.session.completed']

if (req.method === 'POST') {
if (permittedEvents.includes(req.body.type)) {
if (permittedEvents.includes(event.type)) {
try {
switch (req.body.type) {
switch (event.type) {
case 'checkout.session.completed':
await createOrder({ sessionId: req.body.data.object.id })
await createOrder({ sessionId: event.data.object.id })
break
default:
throw new Error(`Unhandled event: ${req.body.type}`)
throw new Error(`Unhandled event: ${event.type}`)
}
} catch (error) {
res.status(500).json({ message: 'Unknown event' })
Expand All @@ -23,3 +30,5 @@ export default async (req, res) => {
res.status(405).json({ message: 'Method not allowed' })
}
}

export default stripeSigningSecret(handler)

1 comment on commit a75467e

@vercel
Copy link

@vercel vercel bot commented on a75467e Mar 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.