The Complete Flow
Everything in one place
Over the last six lessons, we built GitHub login piece by piece. This lesson puts it all together so you can see the complete picture.
The files
src/
app.ts # routes, hooks
server.ts # starts the server
env.ts # environment variables
db.ts # User type, store, findOrCreateFromGithub
sessions.ts # session store
cookies.ts # cookie helpers
auth.ts # authenticate function
oauth-state.ts # CSRF state management
github.ts # GitHub API calls
routes/
github.ts # GET /auth/github, GET /auth/github/callback The data flow
User clicks "Log in with GitHub"
│
├─ GET /auth/github
│ └─ Generate state, store it
│ └─ Redirect to GitHub with client_id, redirect_uri, scope, state
│
├─ User approves on GitHub
│
├─ GET /auth/github/callback?code=...&state=...
│ ├─ Verify state (CSRF protection)
│ ├─ POST github.com/login/oauth/access_token
│ │ └─ Send code + client_secret → receive access_token
│ ├─ GET api.github.com/user (with access_token)
│ │ └─ Receive profile: id, name, avatar
│ ├─ GET api.github.com/user/emails (with access_token)
│ │ └─ Receive emails, pick primary verified
│ ├─ findOrCreateFromGithub(profile)
│ │ └─ Find by GitHub ID or create new user
│ ├─ createSession(user.id)
│ │ └─ Store session in server-side Map
│ └─ Redirect to / with Set-Cookie header
│
├─ User is now logged in
│
└─ GET /me
├─ Read session ID from cookie
├─ Look up session → find user
└─ Return user profile What stays on the server
The access token never leaves your server. The client secret never leaves your server. The session ID travels in a cookie, but the session data stays on the server. The only thing the browser sees is the authorization code (briefly, in a redirect URL) and the session cookie.
What you understand now
If you followed along and built each piece, you now understand:
- What OAuth is and why it exists (delegated authentication)
- The authorization code flow (redirect, consent, code, token exchange)
- Why the code exchange exists (keep the access token off the browser)
- Why the state parameter exists (prevent CSRF on the callback)
- How to call a provider’s API with an access token
- How to create local users from provider profiles
- How OAuth login connects to sessions (the same mechanism as password auth)
This is the same flow that every “Log in with GitHub” button on the internet uses. The libraries (Passport.js, NextAuth, Auth.js) wrap these exact HTTP calls. Now you know what they do internally.
What is next
In Section 3, we add Google as a second provider. This will show you how the pattern repeats: different URLs and different API responses, but the same flow. We will also handle the case where a user signs up with GitHub and later tries Google with the same email (account linking).
Exercises
Exercise 1: Open your browser’s network tab and walk through the entire flow, logging every request. Count the redirects. Identify which requests are browser-to-server, which are browser-to-GitHub, and which are server-to-GitHub.
Exercise 2: Add a logout route if you have not already. The pattern is the same as the auth course: POST /logout, delete the session, clear the cookie. Verify the full cycle: login, view /me, logout, verify /me returns 401, login again (returning user path).
Exercise 3: Try the flow with a GitHub account that has no public email. Verify that the email comes from the /user/emails endpoint instead. Check the server logs or add a console.log to confirm which email source was used.
After the OAuth flow completes, what mechanism keeps the user logged in on subsequent requests?