Skip to content
Ashish.
All posts
Diagram illustrating the three main OAuth 2.0 grant types: Client Credentials, Authorization Code, and PKCE.

OAuth 2.0 Fundamentals: Grant Types Explained Simply

A clear explanation of OAuth 2.0 grant types including authorization code, client credentials, and PKCE for secure API access.

By Ashish SrivastavaPart 1 of OAuth 2.0 Deep Dive Series

When building an application that requires access to a user's data on another service, such as a calendar app retrieving events from Google, the solution is not to store the user's password. Instead, you utilize OAuth 2.0 to request permission to act on the user's behalf. Unlike a single login mechanism, OAuth 2.0 provides a framework of distinct flows known as grant types. Each grant type addresses specific security and trust requirements based on the client's identity and execution environment.

Developers often mistakenly treat OAuth as a monolithic authentication system. In reality, it is a delegation framework where the appropriate grant type is determined by the client's ability to maintain a secret and the presence of a human user. This article serves as an OAuth 2.0 tutorial to detail the mechanisms behind the most critical grant types to prevent common security pitfalls.

The Client Credentials Grant: Machine-to-Machine Trust

The simplest scenario involves communication between two machines without human intervention. This is the Client Credentials Grant, designed for server-to-server background tasks where a machine acts on its own behalf rather than on behalf of a user.

In this flow, the client application is a trusted entity running in a secure environment, such as a microservice or a background worker. Since no user is involved, there is no need for user consent. The client only needs to prove its own identity to the authorization server. The mechanism is direct: the client sends its client_id and a pre-shared client_secret to the token endpoint. The server validates these credentials and immediately issues an access token.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
 
grant_type=client_credentials&
client_id=your_machine_id&
client_secret=your_machine_secret

This flow is strictly restricted to confidential clients. If used in a browser-based JavaScript application, the client_secret would be exposed in the network tab, allowing any user to steal the token. Therefore, this mechanism is reserved for environments where the secret can be kept hidden.

The Authorization Code Grant: The Safe Human Handoff

When a human user is involved, the security model shifts. You cannot ask the user to enter their password into your application, nor should you trust the user to share credentials with a third party. The Authorization Code Grant solves this by exchanging a temporary, short-lived "code" for a long-lived "token" via a redirect loop, ensuring the client never sees the user's password or the access token directly. This flow is foundational for secure API authentication involving user consent.

The mechanism relies on a temporary artifact called an "authorization code." This code is single-use and short-lived. The flow proceeds as follows:

  1. Alice (the user) is on Bob's App (the client).
  2. Bob's App redirects Alice to the Authorization Server (e.g., Google, GitHub).
  3. Alice logs in at the Authorization Server and approves the request.
  4. The Authorization Server redirects Alice back to Bob's App with a code parameter in the URL query string.
  5. Bob's App takes this code and sends it, along with its client_secret, to the Token Endpoint.
  6. The Authorization Server validates the code and the secret, then returns the access_token.

The critical security feature is the separation of channels. The access_token never travels over the open internet in a URL or browser history; it only exists inside the secure server-to-server exchange between Bob's App and the Authorization Server.

While the standard Authorization Code Grant includes client authentication via a client_secret, it is considered insecure for public clients (like mobile apps) that cannot store a secret. Without additional protection, a malicious actor could intercept the code as it returns to the app and use it to steal the token. This vulnerability necessitates the next mechanism.

PKCE: Securing the Public Client

Public clients are applications that cannot securely store a client_secret. This category includes Single Page Applications (SPAs) running in the browser and native mobile apps. Historically, these apps used the "Implicit Grant," which returned tokens directly in the URL fragment. This was dangerous because tokens in URLs are often logged in server logs, browser history, and referer headers.

The industry standard has shifted to Authorization Code Flow with PKCE (Proof Key for Code Exchange). PKCE adds a cryptographic handshake to the standard code flow to prove that the entity requesting the token is the same entity that initiated the authorization request, even without a shared secret.

The mechanism introduces two new variables:

  1. code_verifier: A high-entropy random string generated by the client.
  2. code_challenge: A hash (SHA-256) of the verifier, sent to the authorization server when requesting the code.

The interaction proceeds as follows:

  1. Alice (user) opens Mobile App (client).
  2. Mobile App generates a random code_verifier and stores it locally. It calculates the code_challenge (the hash) and sends this to the Authorization Server in the initial request.
  3. Alice approves the request. The server issues the authorization_code and redirects the app.
  4. Mobile App receives the code and immediately sends the original code_verifier (not the hash) to the Token Endpoint.
  5. The Authorization Server hashes the received verifier and compares it to the code_challenge it received earlier. If they match, the server knows the request came from the same app instance that started the flow.

This prevents an attacker from intercepting the authorization_code in the redirect URL. Even if they steal the code, they cannot exchange it for a token because they do not possess the code_verifier that was never transmitted to the server.

Why Not the Other Flows?

You may encounter references to the Resource Owner Password Credentials (ROPC) grant or the legacy Implicit Grant. These mechanisms are generally unsuitable for modern applications.

The ROPC grant asks the user to enter their username and password directly into the third-party application. This violates the principle that users should never share passwords with anyone other than the identity provider. It also prevents the identity provider from enforcing Multi-Factor Authentication (MFA) properly.

The Implicit Grant was the previous solution for public clients, but it returns the access token directly in the URL fragment (#access_token=...). As noted, tokens in URLs are exposed to the environment. RFC 8252 (OAuth 2.0 Security Best Current Practice for Public Clients) specifically targets public clients and strongly discourages the use of the Implicit Grant in that context, advising that Authorization Code Flow with PKCE be used instead.

Conclusion

Implementing secure API access comes down to matching the right grant type to the client's trust boundary. If it is a server talking to a server, use Client Credentials. If it is a user-driven flow, always use Authorization Code with PKCE.

The confusion often stems from trying to force a single pattern onto every use case. By understanding the mechanism—how the secret is protected, how the code is exchanged, and how the verifier binds the session—you can build systems that remain secure even when the threat landscape evolves.

Common Pitfalls

Even with the correct grant type selected, implementation errors can compromise security. Common mistakes include:

  1. Leaking Client Secrets in SPAs: Attempting to use the Client Credentials grant or storing a client_secret in client-side JavaScript code exposes the secret to anyone who can view the source code or network traffic.
  2. Misusing ROPC: Integrating the Resource Owner Password Credentials grant forces users to trust a third-party app with their primary credentials, bypassing the provider's security controls like MFA.
  3. Storing Tokens in URLs: Redirecting tokens via URL fragments (as in the deprecated Implicit Grant) or query parameters exposes them to server logs, browser history, and referrer headers, making them easy targets for theft.

Practical Takeaways

To ensure your OAuth 2.0 implementation is robust, keep these key points in mind:

  • Match the Trust Boundary: Use Client Credentials for machine-to-machine communication and Authorization Code with PKCE for any user-facing application.
  • Never Hardcode Secrets: Public clients (mobile, SPA) must never rely on a client_secret; instead, implement PKCE to secure the token exchange.
  • Follow Current Standards: Adhere to RFC 8252 for public clients and avoid legacy flows like Implicit Grant or ROPC to prevent known vulnerabilities.

FAQ

Q: Can I use the Authorization Code flow without PKCE for a mobile app? A: No. While the standard Authorization Code flow works for confidential clients (those with a secret), mobile apps are public clients that cannot safely store secrets. Using PKCE is required to prevent code interception attacks in this scenario.

Q: What is the difference between the Authorization Code flow and PKCE? A: The Authorization Code flow is the general mechanism for exchanging a code for a token. PKCE (Proof Key for Code Exchange) is an extension to this flow that adds a cryptographic challenge-response step, allowing public clients to authenticate without a shared secret.

Q: Is the Client Credentials grant suitable for user authentication? A: No. The Client Credentials grant is designed for machine-to-machine communication where the client acts on its own behalf. It does not involve user consent or identity, so it cannot be used to authenticate a specific user.

Related posts