Course outline · 0% complete

0/29 lessons0%

Course overview →

OAuth and the Security Checklist

lesson 7-4 · ~11 min · 23/29

OAuth: "Log in with Google", demystified

Sometimes you do not want passwords at all. OAuth lets users prove their identity through an account they already have (Google, GitHub). The flow, simplified:

  1. Your app redirects the user to the provider: "this app would like to know who you are".
  2. The user consents on the provider's site. Their password is typed there, never on yours.
  3. The provider redirects back to your app with a one-time code.
  4. Your server exchanges that code (plus its own client secret) directly with the provider for a token, and reads the user's identity from it.
  5. From here you are back in known territory: create the user row, start a session or issue your own JWT (lessons 7-2 and 7-3).

The key mental model: OAuth outsources the proving who you are step to someone users already trust, and hands your server a verifiable result.

Why a one-time code instead of the token itself

Because URLs leak, through browser history, server logs, and referer headers, so the real token is fetched server-to-server where nothing user-visible can carry it away.

Anything in a URL ends up in histories, proxies, and logs. A token in a redirect URL would be recorded in the user's browser history, in any analytics that captures the landing URL, and in the access logs of every hop that saw the request.

The one-time code is useless without your app's client secret, which is the property that makes it safe to expose. Even someone who reads the code out of a log cannot exchange it, and the code is single-use and short-lived on top of that.

The code-for-token exchange happens directly between your server and the provider over TLS (Transport Layer Security), the encryption layer that wraps a connection so nobody along the network path can read or tamper with it. TLS is the S in HTTPS.

Sensitive material stays out of the browser entirely, which is the general principle worth carrying beyond OAuth. Anything a browser holds can be read by scripts, extensions, and whoever borrows the laptop, so secrets belong on the server side of the conversation.

Where the GitHub password gets typed

On GitHub's own site, and your server only ever receives the one-time code and then a token.

This is the entire point of the redirect dance, since credentials only ever touch the provider. The user leaves your app, authenticates somewhere they already trust, and comes back with a result your server can verify.

If your app collects GitHub passwords itself, you take custody of a secret you never needed and train users to type passwords into the wrong sites, which is exactly how phishing works. The habit of refusing to accept another site's credentials is a security feature for the whole ecosystem, not just for you.

The practical benefits stack up quickly. There is no password to hash, no reset flow to build, no breach exposure for credentials you do not hold, and two-factor authentication comes free from the provider.

Your server exchanges the code plus its client secret for a token, server-to-server, and never sees the password. What it gets instead is an identity it can trust, which is all it needed in the first place.

The checklist

Authentication mistakes are the expensive kind. Before shipping any login system:

  • Never roll your own crypto. Lessons 7-1 and 7-3 taught the mechanics so you understand them, production uses bcrypt/argon2 and a maintained JWT library (jsonwebtoken, jose).
  • Hash passwords with bcrypt or argon2, salted, never plain, never SHA-256 alone.
  • HTTPS everywhere. HTTPS is simply HTTP carried over TLS, the encryption layer from the quiz above. Tokens and cookies sent over plain HTTP are readable by anyone on the network path: coffee-shop wifi, a compromised router, your ISP.
  • Cookies: httpOnly + secure, so page scripts cannot read them (the httpOnly flag from lesson 7-2) and the browser refuses to send them over plain HTTP (secure).
  • Rate limit login attempts (unit 8), or attackers guess passwords all day.
  • Keep error messages generic: "invalid email or password", never "wrong password", which confirms the email exists and hands attackers a user list.
  • Secrets live in environment variables, never hardcoded in source files. Your code is tracked by git, the standard version-control tool that permanently records every past version of every file, and is usually pushed to GitHub, a site that hosts git projects for a team or the public. A secret committed once is therefore readable by anyone who ever gets access to the project, even after you delete it, because the history keeps it. Unit 8 starts exactly there.

Where a signing secret belongs

Environment variables.

Code in a repository is visible to everyone with repo access, forever, and git history keeps deleted secrets too. Removing the line in a later commit does not remove it from the history, which is why a committed secret has to be rotated rather than merely deleted.

Secrets belong in the process environment, read via process.env.JWT_SECRET, and injected differently per machine. A local .env file serves development, and your host's secret manager serves production.

The stakes are as high as they get for a signing secret. Anyone who finds it can mint valid admin tokens, so a leak is not a partial compromise, it is every account at once with no trace in the logs.

Lesson 2-3 introduced the process object that exposes these, and the checklist's last line names the rule. Unit 8 is built around it, starting with how to validate that the required values are actually present.