What is OAuth 2.0?

Understanding modern authorization flows, tokens, and securing APIs.

Before OAuth, if a printing service wanted to access your Google Drive photos to print them, you had to give the printing service your actual Google username and password. This was a massive security nightmare—the printing service had full control over your entire Google account, not just your photos.

OAuth 2.0 (Open Authorization) solves this. It is an industry-standard protocol for authorization. It allows a user to grant a third-party application limited access to their resources on another site, without ever sharing their password.

Authentication vs. Authorization

This is the most common point of confusion:

  • Authentication (AuthN): Verifying who you are (e.g., checking a username and password).
  • Authorization (AuthZ): Verifying what you are allowed to do (e.g., granting read access to photos).

OAuth 2.0 is strictly an Authorization protocol. To handle Authentication, the industry built OpenID Connect (OIDC) on top of OAuth 2.0.

The OAuth 2.0 Actors

To understand the flow, you must understand the four primary actors involved:

  1. Resource Owner: The user (You).
  2. Client: The application requesting access (The printing service).
  3. Resource Server: The API hosting the data (Google Drive API).
  4. Authorization Server: The server issuing tokens (Google's login/consent server).

The Authorization Code Flow (with PKCE)

There are multiple ways to get an OAuth token (called "Grants"), but the Authorization Code Flow with PKCE is the current gold standard for almost all web and mobile applications.

  1. The User clicks "Login with Google" on the Client app.
  2. The Client redirects the User's browser to the Authorization Server, passing a client_id, the requested scopes (e.g., read:photos), and a cryptographically generated code_challenge (this is the PKCE part).
  3. The User logs into Google and sees a consent screen: "PrintingService wants to view your photos. Allow?"
  4. The User clicks "Allow". The Authorization Server redirects the User back to the Client with a temporary Authorization Code.
  5. The Client takes that Authorization Code, adds the code_verifier (the secret behind the earlier PKCE challenge), and sends a background HTTP POST request to the Authorization Server.
  6. The Authorization Server verifies everything and responds with an Access Token (and often a Refresh Token).
  7. The Client uses the Access Token to make requests to the Resource Server (Google Drive API).

Access Tokens vs. Refresh Tokens

Access Tokens

The Access Token is the actual key to the API. It is passed in the HTTP Authorization: Bearer header. Access Tokens should have a very short lifespan (e.g., 15 minutes to 1 hour). If a hacker steals an Access Token, their access is quickly revoked when it expires. Often, Access Tokens are formatted as JWTs (JSON Web Tokens).

// Making an authenticated API request
fetch('https://api.example.com/data', {
  headers: {
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...'
  }
});

Refresh Tokens

If Access Tokens expire in 15 minutes, why don't you have to log in to Spotify every 15 minutes? Because of the Refresh Token.

A Refresh Token is a long-lived credential (e.g., lasts 30 days) that is used only to request new Access Tokens from the Authorization Server. It is never sent to the Resource Server API. If a Refresh Token is compromised, it can be explicitly revoked by the server.

Why PKCE Replaced the Implicit Flow

Historically, Single Page Applications (SPAs) like React or Vue used the "Implicit Flow," where the Authorization Server returned the Access Token directly in the URL hash fragment. This was incredibly insecure, as the token could be logged in browser history or stolen by malicious JavaScript.

Furthermore, SPAs cannot securely store a "Client Secret" because all JavaScript is visible to the end-user.

PKCE (Proof Key for Code Exchange) solves this. Instead of a static hardcoded Client Secret, the SPA dynamically generates a random secret (verifier) and a hash of that secret (challenge) for every single login attempt. This proves to the server that the application requesting the final token is the exact same application that initiated the login, without needing a permanent secret.

Common OAuth Mistakes

  • Storing tokens in LocalStorage: LocalStorage is vulnerable to XSS (Cross-Site Scripting) attacks. In web apps, tokens should be stored in Secure, HttpOnly cookies.
  • Not validating scopes: Just because a token is valid doesn't mean it has permission to do the requested action. Your API must verify that the token's scopes include the required permissions.
  • Trusting JWTs without verifying signatures: Always verify the cryptographically signed signature of a JWT before trusting the data inside it.