Skip to content

Stripe 웹훅

이 문서에서는 Hono를 사용해 Stripe 웹훅 이벤트를 수신하는 API를 만드는 방법을 소개한다.

준비

먼저 공식 Stripe SDK를 설치한다:

bash
npm install stripe

그리고 .dev.vars 파일에 다음 값을 추가해 Stripe API 키를 설정한다:

STRIPE_API_KEY=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx

Stripe API 키에 대해 더 알아보려면 다음 문서를 참고한다:

Stripe 웹훅 이벤트를 위한 API 보호 방법

웹훅 이벤트를 처리하는 API는 공개적으로 접근 가능하다. 따라서 악의적인 제3자가 Stripe의 웹훅 이벤트 객체를 위조해 요청을 보내는 등의 공격으로부터 보호하기 위한 메커니즘이 필요하다. Stripe의 경우, 웹훅 시크릿을 발급하고 각 요청을 검증함으로써 API를 보호할 수 있다.

자세히 알아보기: https://docs.stripe.com/webhooks?lang=node#verify-official-libraries

호스팅 환경 또는 프레임워크별 웹훅 API 구현

Stripe에서 서명 검증을 수행하려면 원본 요청 본문이 필요하다. 프레임워크를 사용할 때는 원본 본문이 수정되지 않도록 주의해야 한다. 원본 요청 본문에 어떤 변경이 발생하면 검증이 실패한다.

Hono의 경우 context.req.text() 메서드를 통해 원본 요청 본문을 얻을 수 있다. 따라서 다음과 같이 웹훅 API를 구현할 수 있다:

ts
import Stripe from 'stripe'
import { Hono } from 'hono'
import { env } from 'hono/adapter'

const app = new Hono()

app.post('/webhook', async (context) => {
  const { STRIPE_SECRET_API_KEY, STRIPE_WEBHOOK_SECRET } =
    env(context)
  const stripe = new Stripe(STRIPE_SECRET_API_KEY)
  const signature = context.req.header('stripe-signature')
  try {
    if (!signature) {
      return context.text('', 400)
    }
    const body = await context.req.text()
    const event = await stripe.webhooks.constructEventAsync(
      body,
      signature,
      STRIPE_WEBHOOK_SECRET
    )
    switch (event.type) {
      case 'payment_intent.created': {
        console.log(event.data.object)
        break
      }
      default:
        break
    }
    return context.text('', 200)
  } catch (err) {
    const errorMessage = `⚠️  Webhook signature verification failed. ${
      err instanceof Error ? err.message : 'Internal server error'
    }`
    console.log(errorMessage)
    return context.text(errorMessage, 400)
  }
})

export default app

관련 자료

Released under the MIT License.