Step 4 — GitHub OAuth & Webhooks

What This Step Is About

This step implements two of the most technically interesting parts of the project: letting users log in with their GitHub account (OAuth), and receiving real-time events from GitHub when code is pushed or a PR is opened (Webhooks). Both are standard patterns in production web applications and come up frequently in interviews.


Concepts and Tools

OAuth 2.0

OAuth is an authorization protocol that lets a user grant your application access to their account on another service (GitHub, Google, etc.) without sharing their password with you. The user trusts GitHub; GitHub vouches for them to your app.

The flow for GitHub OAuth has four steps:

  1. Your app redirects the user to GitHub with your app's client_id and the permissions you are requesting (scope).
  2. The user approves on GitHub. GitHub redirects them back to your callback URL with a temporary code.
  3. Your server exchanges that code for an access_token by making a server-to-server POST request to GitHub (using both your client_id and client_secret). This exchange happens on the server, not in the browser, so your secret is never exposed.
  4. Your server uses the access_token to call the GitHub API and get the user's profile. You then create or update their record in your database.

The state parameter in step 1 is a CSRF (Cross-Site Request Forgery) protection measure — a random value you generate and later verify is the same one GitHub returns in the callback, ensuring the callback was initiated by your app and not a third party.

Resources:

CSRF (Cross-Site Request Forgery)

CSRF is an attack where a malicious site tricks a user's browser into making a request to your server. In the OAuth context: an attacker could forge a callback URL with a stolen code and redirect it to your callback endpoint, potentially logging in as someone else.

The state parameter mitigates this. You generate a random value before the redirect, store it (in a session or cookie), and verify it matches when GitHub calls back. If it does not match, reject the request. The implementation in this project notes this pattern — for a portfolio project without sessions, you can log the state mismatch but a full session-based implementation is the correct production approach.

Resources: