12. Chapter review
You have taken OAuth from a vague "sign in with..." button to a concrete Python flow: register an app, understand state and PKCE, build a safe authorization URL, catch the callback, exchange the code, save the access token safely for a local test, call GitHub with a bearer token, and combine the pieces into a complete command-line tool.
What you've mastered
- Delegated access. You can explain why OAuth gives an app limited permission instead of the user's password.
- OAuth roles. You can identify the resource owner, client, authorization server, and resource server in the GitHub flow.
- Authorization code flow. You know why GitHub returns a temporary code first, then expects your app to exchange that code for a token.
- State validation. You generate unpredictable
state, carry it through the flow, and reject mismatched callbacks before token exchange. - PKCE. You generate a
code_verifier, send a derivedcode_challenge, and use the verifier during token exchange as a per-flow proof. - GitHub setup. You can register a GitHub OAuth App, configure a local callback URL, load credentials from a gitignored
.envfile, and keep secrets out of Git. - Token hygiene. You call APIs with bearer tokens, mask token output, avoid hardcoding or casual sharing, and distinguish the split scripts' gitignored
.envstorage from the final tool's in-memory token handling. - Scope judgment. You start narrow with
read:user, understand that repository scopes are broader, and treatrepoas a serious permission. - Lifecycle thinking. You understand the provider-general pattern for expiring access tokens, refresh tokens, retry-once behavior, and revocation, while recognizing that GitHub OAuth Apps are not the main refresh-token example.
- OAuth debugging. You can map failures to the step that caused them: callback URL, state, PKCE verifier, client credentials, expired code, token header, or scope.
Check your understanding
Read each question, say your answer out loud or type it, then reveal the explanation. If one feels fuzzy, return to the matching page before moving on.
Select a question to reveal the answer:
Why does OAuth use an authorization code instead of putting the access token directly in the browser redirect?
The browser redirect is an exposed handoff. URLs can appear in history, logs, screenshots, extensions, and debugging output. OAuth sends a temporary authorization code through that handoff, then requires a separate token exchange before issuing the access token. With PKCE, the exchange also needs the original code_verifier, so an intercepted code is not enough by itself.
What jobs do state, code_challenge, and code_verifier each perform?
They bind the flow together in different ways. state binds the callback to the browser flow your app started and protects against CSRF-style callback swapping. code_challenge is the public PKCE value sent in the authorization URL. code_verifier is the temporary secret your app keeps and sends during token exchange to prove it started the original request.
Your first GitHub call to /user works, but a repository endpoint fails with a scope error. What should you do?
Do not blindly add repo. First identify what the feature actually needs. Public repository inspection may call for a narrower repository scope. Private repository access is a much bigger request and should be explained to the user before re-authorization. For production GitHub integrations, also consider whether a GitHub App with fine-grained permissions is the better model.
Why is printing the full access token, or pasting it into a Python file, a bad teaching habit?
Bearer tokens are credentials. Whoever has the token can use it until it expires or is revoked. Printing full tokens turns terminal history, screenshots, logs, and copied output into credential storage. Hardcoding tokens makes accidental commits likely. In the learning flow, the callback script saves the token to a gitignored .env file, later scripts load it from there, and terminal output shows only a masked preview.
How do the three split scripts hand OAuth data from one step to the next?
Each script owns one handoff. 1_authorization_url.py creates the authorization URL and prints the temporary state and code_verifier. 2_callback_exchange.py reads those values, checks returned state, exchanges the code with the verifier, and saves GITHUB_ACCESS_TOKEN to .env. 3_github_request.py loads that token and sends it in the bearer-token header.
A provider issues one-hour access tokens and refresh tokens. What should a token manager do before each API request?
Check expiry with a safety buffer. If the access token is expired or close to expiring, refresh it before making the request. If the provider still returns a 401 because the token expired between check and use, refresh and retry once. If refresh fails because the token was revoked or expired, clear stored tokens and ask the user to reconnect.
When GitHub redirects to your callback, what must your app check before exchanging the code?
Check for errors, state, and code. If GitHub returned an error, handle it instead of exchanging. If returned state does not match the value your app generated, abort before token exchange. If there is no code, there is nothing to exchange. Only after those checks should your app send the code, client credentials, redirect URI, and PKCE verifier to the token endpoint.
Looking forward
OAuth answers the question "Who can access what?" You can now connect a user's account safely, request a narrow permission, verify that the callback belongs to the flow you started, and call an API without handling the user's password.
But your programs are still temporary. They fetch data, print results, and forget everything when they exit. Useful applications need memory: cached API responses, historical records, user preferences, and data you can query later.
In the next chapter, Chapter 15: Database Fundamentals with SQLite, you'll learn how to give API programs durable state. You'll build a weather API cache and see how a database turns one-off API calls into application memory.
Chapter 16 then applies OAuth again in a richer project: the Spotify Music Time Machine. The PKCE, scopes, token handling, and lifecycle patterns you learned here will make that library-managed OAuth flow easier to trust and debug.
You've learned how to connect safely. Next, you'll learn how to remember.