Module 4 · Authentication and security

Lesson 19 — OAuth2 and OpenID Connect

Flows, scopes and why "sign in with Google" is harder than it looks.

Published
In this lesson
  1. Exercise 1 — The flow, observed
  2. Exercise 2 — The id_token under the magnifying glass
  3. Exercise 3 — Account linking (the classic pitfall)
  4. Exercise 4 — Your API with scopes (a preview of 21)
  5. Exercise 5 — ADR-0009: "Sign in with Google (OIDC)"
  6. Exercise 6 — Scopes and the flow map
  7. Submit

Google account + a project in Google Cloud Console (free OAuth credentials). Don't look at solutions.md before submitting.

Exercise 1 — The flow, observed

  1. Configure django-allauth with the Google provider (client_id/secret in per-environment settings — 27). Start it and do the full login from your app.
  2. During the flow, capture (DevTools → Network): the /authorize URL (are code_challenge and state there?), the redirect with ?code=, and the redemption call. List the lesson's 6 steps seen in your own traffic.
  3. Change the state in the callback by hand and repeat: what error? Which attack does that validation prevent?

Exercise 2 — The id_token under the magnifying glass

  1. Paste the id_token into jwt.io: list the claims (iss, aud, sub, email, email_verified, exp, iat, nonce).
  2. Verify the signature against Google's public JWKS (https://www.googleapis.com/oauth2/v3/certs): which key matches by kid?
  3. List the 4 minimum checks your backend would make besides the signature, and which attack each one prevents.

Exercise 3 — Account linking (the classic pitfall)

  1. Scenario A: a user registered with email+password (verified email). Then they sign in with Google with THE SAME verified email. What should happen? Implement the linking.
  2. Scenario B: an unverified Google email (a provider that doesn't verify) with the same email: what does your code do? Implement the rule: never link without email_verified=true.
  3. Scenario C: same human, two providers (Google + GitHub with different emails): two accounts? A manual unification mechanism? Decide and record it in the ADR.

Exercise 4 — Your API with scopes (a preview of 21)

  1. If TicketFlow exposed an API to integrators: define 3 scopes (events:read, tickets:write, refunds:write) and the check in your viewsets (has_permission by scope).
  2. Write the 403 response with the missing scope (RFC 7807 format, type: missing-scope).

Exercise 5 — ADR-0009: "Sign in with Google (OIDC)"

Context (registration friction, free email verification), decision (allauth + OIDC + linking by verified email), alternatives (password+MFA only, magic links), consequences (provider dependency only at login, JWKS caching, local account always).

Exercise 6 — Scopes and the flow map

  1. Implement TicketFlow's 5 scopes (§6) in your fake IdP and add the per-endpoint scope-verification middleware: the checkout demands tickets:purchase, the organizer panel organizer:*. Test: a token without the scope → 403 with problem+json (26) saying WHICH scope was missing.
  2. Human consent: write the consent screen (or JSON) the user sees: each scope translated into human language (51: the two-way translation). How do you explain "tickets:purchase" to your aunt?
  3. The flow-meter: classify 4 real integrations of your project in the §5 table (the worker→gateway, the buyer's login, the physical box-office terminal, the old SPA you inherited). Which one demands a migration and why?

Submit

Paste claims, checks and linking decisions. Next: Lesson 20 — Password hashing and MFA.