Phase 3: Authentication & Security

OAuth2 flows: authorization code, PKCE & client credentials

Intermediate ~2 min read
Think of it this way A friendly analogy. Read this if the technical version feels dense. Show Hide

You know how sometimes you want to use a special toy from your friend's toy chest for your big fort-building project, but you don't want to give your friend the key to their entire chest? That's kind of like how your favorite apps, like a photo editor or a game, want to use some of your stuff from a bigger online service, like your pictures on Google Photos or your game scores on a gaming platform. You want them to help with your project, but you definitely don't want to give them your secret password to that big service!

This is where a clever system called "OAuth2" comes in, like a super-smart way to share. Imagine your fort-building project is an app on a website, and it needs a special "golden brick" from Google Photos. Your project app sends you to Google Photos' official "toy chest manager" (their login page). You log in directly to Google Photos with your password – your project app never even sees it! Google Photos asks, "Do you want to let Fort-Builder App get this special golden brick for your project?" You say yes. Instead of giving the brick directly to your app, Google Photos gives you a temporary "pickup slip" for the brick. You quickly bring this pickup slip to your Fort-Builder App's secret "back room" (its secure computer server). In that back room, your app combines the pickup slip with its own secret "app ID card" and sends both securely, behind the scenes to Google Photos' secret "back office." Google Photos then gives your app a special "borrowing pass" for that golden brick. Now your app can use the golden brick for your project, all without ever seeing your password!

But what if your fort-building app is on your phone or a website that doesn't have a super-secret "back room" to hide its "app ID card"? That's where a trick called "PKCE" (which means "Proof Key for Code Exchange") helps. Before you even go to Google Photos, your phone app invents a secret "handshake code" and gives Google Photos a scrambled version of it. When you get the "pickup slip" and send it back to your app, your app sends the original, unscrambled handshake code along with it to Google Photos. Google Photos checks if the handshake matches its scrambled version. If it does, Google Photos knows it's really your app, not some imposter who grabbed your pickup slip. This means your phone app can still get the "borrowing pass" safely, even without a secret "app ID card" of its own.

Sometimes, an app just needs to talk to another service directly, without you being involved at all – like your app asking Google Photos, "How many golden bricks are in stock today?" In those cases, your app simply shows its "app ID card" directly to Google Photos' back office to get a temporary pass for general information. So, when you build your own apps someday, this clever system means you can let them use features from big services safely, keeping your own secret passwords truly secret!

The Authorization Code flow is the most common and secure OAuth2 flow for web applications with a backend (confidential clients). Here, when a user wants to grant your application access to their data on another service (like Google or GitHub), they are first redirected to that service's authorization page. After the user approves, the service redirects them back to your application with a temporary authorization code. Your backend then securely exchanges this code, along with your application's client_id and client_secret, directly with the authorization server to obtain an access_token (and often a refresh_token). This backend-to-backend exchange keeps sensitive tokens out of the user's browser, preventing interception and ensuring only your trusted backend receives the access token.

For "public clients" like mobile apps or Single Page Applications (SPAs) that lack a secure backend to store a client_secret, the Authorization Code flow with PKCE (Proof Key for Code Exchange) offers enhanced security. PKCE adds a dynamic secret to the authorization process without requiring a pre-registered client secret. The client first generates a random code_verifier and sends its cryptographic hash, the code_challenge, with the initial authorization request. When exchanging the authorization code for an access_token, the client sends the original code_verifier. The authorization server then verifies that the code_challenge matches the code_verifier, ensuring that the same client that initiated the request is the one completing the token exchange. This prevents malicious clients from intercepting and misusing authorization codes.

The Client Credentials flow is fundamentally different, designed for machine-to-machine communication where there's no user involved. Think of a backend service that needs to access an API on another service without a user's explicit permission (e.g., a microservice calling another microservice to retrieve internal data). In this flow, the client application itself directly authenticates with the authorization server by providing its client_id and client_secret. Upon successful authentication, the authorization server issues an access_token directly to the client. This token is then used by the client to access protected resources on a resource server. This flow is ideal for automated processes and service-to-service interactions where client applications are trusted and can securely store their credentials.

Key Takeaways

  • Authorization Code: Secure for web applications with backends, involving user redirection and a secure backend token exchange.
  • PKCE: Enhances Authorization Code for public clients (SPAs, mobile) by using a dynamic secret to prevent authorization code interception without a static client secret.
  • Client Credentials: For machine-to-machine communication; no user involved, client authenticates directly with ID/secret for API access.
  • Choose the appropriate OAuth2 flow based on your client type (confidential vs. public) and whether an end-user is present in the interaction.

Code Example

bash
curl -X POST \
  https://your-auth-server.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"

How this code works

This code makes an HTTP request to an authorization server to obtain an access token. Specifically, it uses the client_credentials OAuth2 flow, designed for secure machine-to-machine communication where an application needs to access resources directly, without an end-user being present. The curl command initiates a POST request to the server's /oauth/token endpoint, which is the standard place for requesting tokens.

The request sends application credentials in its body using the -d flag. It declares the grant_type as client_credentials, indicating the specific OAuth2 flow being requested. Then, it provides the application's unique client_id and client_secret, which authenticate the application itself to the server. A subtle but important detail is the -H "Content-Type: application/x-www-form-urlencoded" header. This header explicitly tells the server how to interpret the data in the -d body, ensuring the key=value pairs are correctly parsed. Failing to include or correctly set this header is a common beginner mistake that can prevent the server from understanding the request.