DEV Community

Rishi Raj Jain
Rishi Raj Jain

Posted on

Automating access to a GitHub Repo using Stripe Webhooks and Astro Endpoints

In this tutorial, I'll walk you through the steps of leveraging Astro Endpoints to verify Stripe Webhooks, and seamlessly grant access to a GitHub repository, all condensed into concise and developer-friendly code. I'll dissect the process into digestible steps, making it effortless for you to integrate these powerful features into your web projects.

Prerequisites

Before we dive into the process, make sure you have the following prerequisites in place:

Installation

Once setup with prerequisites, install stripe npm package via:

npm install stripe
Enter fullscreen mode Exit fullscreen mode

Add Stripe environment variables

Add Stripe Secret Key as STRIPE_SECRET_KEY & Webhook Signing Secret as STRIPE_WEBHOOK_SIG as the environment variables in your environment (usually it is an .env file).

Create Webhook Handler Endpoint in your Astro project

// File: src/pages/api/stripe/webhook.ts

// Stripe API Reference
// https://stripe.com/docs/webhooks#webhook-endpoint-def
export async function POST({ request }: APIContext) {
  try {
    const STRIPE_SECRET_KEY = import.meta.env.STRIPE_SECRET_KEY
    const STRIPE_WEBHOOK_SIG = import.meta.env.STRIPE_WEBHOOK_SIG
    const GITHUB_PAT_TOKEN = import.meta.env.GITHUB_PAT_TOKEN
    if (!STRIPE_SECRET_KEY || !STRIPE_WEBHOOK_SIG || !GITHUB_PAT_TOKEN) {
      return new Response(null, {
        status: 500,
      })
    }
    const stripe = new Stripe(STRIPE_SECRET_KEY, { apiVersion: '2023-08-16' })
    // Verify Stripe Signature to protect the endpoint
    // Send GitHub Access to the repo once verified
  } catch (e) {
    return new Response(e.message || e.toString(), { status: 500 })
  }
}
Enter fullscreen mode Exit fullscreen mode

Verify Stripe Signature in your Astro Endpoint

To verify stripe signatures, you need to get access to the raw body. Use the rawBody function to get that done for you πŸ‘‡πŸ»

// File: src/pages/api/stripe/webhook.ts

// Process rawBody from the request Object
async function getRawBody(request: Request) {
  let chunks = []
  let done = false
  const reader = request.body.getReader()
  while (!done) {
    const { value, done: isDone } = await reader.read()
    if (value) {
      chunks.push(value)
    }
    done = isDone
  }
  const bodyData = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0))
  let offset = 0
  for (const chunk of chunks) {
    bodyData.set(chunk, offset)
    offset += chunk.length
  }
  return Buffer.from(bodyData)
}
Enter fullscreen mode Exit fullscreen mode

With that done, now verify the request using the rawBody function as below using stripe's constructEvent function πŸ‘‡πŸ»

// File: src/pages/api/stripe/webhook.ts

export async function POST({ request }: APIContext) {
    // Verify Stripe Signature to protect the endpoint
    const rawBody = await getRawBody(request)
    let event = JSON.parse(rawBody.toString())
    const sig = request.headers.get('stripe-signature')
    try {
      event = stripe.webhooks.constructEvent(rawBody, sig, STRIPE_WEBHOOK_SIG)
    } catch (err) {
      console.log(err.message)
      return new Response(`Webhook Error: ${err.message}`, {
        status: 400,
      })
    }
    // Send GitHub Access to the repo once verified
}
Enter fullscreen mode Exit fullscreen mode

Add GitHub environment variable

Add GitHub Personal Access Token as GITHUB_PAT_TOKEN as an environment variable in your environment (usually it is an .env file).

Send GitHub Access to the repo once verified

To send access to a GitHub repo, you need to make a PUT request using the GitHub API. Use the sendAccess function to get that done for you πŸ‘‡πŸ»

// File: src/pages/api/stripe/webhook.ts

// Send access to a github repo using custom field in Stripe checkout
async function sendAccess(paymentIntent) {
  const username = paymentIntent['custom_fields'].find((i) => i.key === 'githubusername').text.value
  await fetch(`https://api.github.com/repos/repo-owner/repo-name/collaborators/${username}`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `token ${import.meta.env.GITHUB_PAT_TOKEN}`,
    },
    body: JSON.stringify({ permission: 'read' }),
  })
}
Enter fullscreen mode Exit fullscreen mode

With that done, now select the Stripe Events for which you need to automate the access. Right now, I'm demonstrating sending access when a Checkout Session is completed or a Payment is made successfully πŸ‘‡πŸ»

// File: src/pages/api/stripe/webhook.ts

export async function POST({ request }: APIContext) {
    // Send GitHub Access to the repo once verified
    if (event.type === 'checkout.session.completed') {
        return await sendAccess(event.data.object)
    }
    if (event.type === 'payment_intent.succeeded') {
        return await sendAccess(event.data.object)
    }
}
Enter fullscreen mode Exit fullscreen mode

You're Done!

You've successfully set up verification of Stripe Webhooks and automated granting access to a GitHub repository using Astro Endpoints. This powerful combination of technologies allows you to create seamless payment and access management for your web projects.

Happy coding!

Top comments (2)

Collapse
 
tobysolutions profile image
Tobiloba Adedeji

Amazing, stuff!!!!!

Collapse
 
reeshee profile image
Rishi Raj Jain

Thank you, Tobiloba!