# OAuth 2.0: The Grant Types, Explained — Routebase

> The four roles, the grants that matter today, why PKCE is now required for every authorization code flow, and what RFC 9700 has retired.

Canonical page: https://routebase.dev/guides/api-authentication/oauth-2-grant-types/
Chapter 4 of 11 · API Authentication · Last reviewed 2026-09-12 · The Routebase Team

OAuth 2.0 has a reputation for complexity. Most of that reputation comes from trying to read about all of the grants at once. The framework itself is small, and the difficulty comes from what it had to cover. Browser applications, mobile applications, server-side applications and machines all differ in their ability to keep a secret.

Start with the four roles, then pick the one grant your situation calls for and ignore every other one.

## The four roles

| Role | Who it is |
|---|---|
| Resource owner | The user who owns the data, or nobody when a machine acts for itself |
| Client | The application asking for access |
| Authorization server | The thing that authenticates the owner and issues tokens |
| Resource server | The API that accepts the token |

The distinction that matters most is between the authorization server and the resource server. They are frequently the same deployment. Treating them as one concept is how people end up with an API that mints its own tokens and calls the result OAuth.

A second distinction runs through everything below, and it decides which grant applies. A **confidential client** can keep a secret, because it runs on a server you control. A **public client** cannot, because its code ships to a browser or a phone where anyone can read it.

## Client credentials, for machines

There is no user in this flow, so there is nothing to delegate and no redirect to perform. The client authenticates with its own credentials and receives an access token in return.

```txt
POST /oauth/token
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=orders.read
```

This is the grant for a background job, a service-to-service call or a partner integration. It is the closest thing OAuth has to an API key, with two differences that are usually worth the extra step. The token is short-lived, so a leak has a deadline. Revocation happens centrally at the authorization server instead of in each API.

The client credentials can travel two ways, either as HTTP Basic on the token request or as parameters in the body. RFC 6749 defines both and prefers the header. Some servers only accept one, so this is a setting and not a preference.

## Authorization code with PKCE, for everything with a user

This is the grant to use whenever a person is delegating access to an application. It works for server-side web applications, single-page applications and mobile applications alike.

_Figure: The front channel carries only a short-lived code through the browser, and the token appears on the back channel between two servers._

```txt
1.  The client generates a random code_verifier and derives
    code_challenge = BASE64URL(SHA256(code_verifier))

2.  Redirect the user to the authorization server
    GET /authorize?response_type=code&client_id=…&redirect_uri=…
        &scope=orders.read&state=xyz
        &code_challenge=…&code_challenge_method=S256

3.  The user authenticates and consents

4.  Redirect back with a short-lived code
    GET https://app.example/callback?code=…&state=xyz

5.  The client exchanges the code for tokens
    POST /oauth/token
    grant_type=authorization_code&code=…&redirect_uri=…
        &client_id=…&code_verifier=…
```

Two parameters in that exchange do all of the security work, and both are easy to skip.

**`state`** is a value the client generates and checks on return. It ties the callback to the request the client actually started, and that is what prevents cross-site request forgery on the redirect.

**PKCE**, defined in RFC 7636, ties the code to the client. Because the challenge is sent at step two and the verifier only at step five, an attacker who intercepts the code at step four cannot redeem it. RFC 9700 extends this requirement from public clients to every authorization code flow, since the protection costs nothing.

The redirect URI has to be registered in advance and matched exactly when the browser comes back. Wildcard or prefix matching is how authorization codes end up delivered to an attacker-controlled path.

## The two grants you should not use

**Implicit.** It returned the access token directly in the URL fragment, so the token landed in the browser history, in anything reading the page, and potentially in a referrer header. There was no client authentication and no refresh path. RFC 9700 states plainly that it should no longer be used, and authorization code with PKCE covers the same case properly.

**Resource owner password credentials.** The client collects the user's username and password and exchanges them for a token. That is the exact thing OAuth was invented to avoid, it defeats multi-factor authentication, and it makes every client a place where passwords are handled. RFC 9700 retires it too. Where you find it in the wild it is usually a first-party mobile application from before the alternatives were mature.

Both still appear in tools and in vendor documentation, and both remain necessary on occasion when you integrate with something old. Knowing why they are retired is what lets you argue for a migration.

## Scopes, and where they stop

A scope is a string the client requests and the authorization server may grant, and it appears in the resulting token. Two properties of a scope need stating clearly before you rely on one.

Scopes are coarse by design, and that coarseness is the part people misread. `orders.read` says the client may read orders, and it says nothing whatever about whose orders. That second question is authorization on the resource server, and no scope answers it. An API that treats a valid scope as sufficient has broken object level authorization by construction.

Scopes are a request, not a grant. A client asking for five scopes may receive three, so the token has to be read for what it carries and not for what was asked.

## Token lifetimes in practice

| Token | Reasonable lifetime | Why |
|---|---|---|
| Access token | Minutes to an hour | It is a bearer credential, so its lifetime is your exposure window |
| Refresh token | Days to months, rotated on use | It is revocable, so it can live longer safely |
| Authorization code | Seconds, single use | It only has to survive one redirect |

Refresh token rotation repays the implementation effort it costs. Issue a new refresh token on every redemption, invalidate the old one, and treat a reused token as a compromise of the whole chain.

## In Routebase

OAuth 2.0 is one entry in the authentication catalogue, and it supports four grant types. Those are Client Credentials, Authorization Code, Authorization Code with PKCE and Password Credentials marked as legacy. The last one is there because integrations still require it, and the guidance above about not choosing it for new work stands.

_Screenshot: Client credentials, scope and audience all accept variable references, and the token manager keeps what the grant returned._

The configuration covers everything a real provider is likely to ask for. There are fields for the token URL, the authorization URL and the callback URL, plus the client identifier and secret, the scope, the audience and the state. A header prefix is configurable, and client authentication travels either as a Basic header or in the request body. Custom parameters can be added to the token request, the authorization request and the refresh request separately. That is what makes a provider with a non-standard parameter workable without leaving the tool.

A token manager sits below the form, per environment. Each stored token appears with its grant type and its expiry, and the controls beside it request a new one, refresh, copy or delete. Tokens belong to the environment that fetched them, and they deliberately never travel when an authentication configuration is copied to another environment, because the target has to fetch its own.

Every credential field accepts a `{{VARIABLE}}` placeholder, so the client secret lives in a secret variable. **Test Authentication** fires one probe with the configured credentials and shows you what came back. That is the fastest way to find out that a token URL or a scope is wrong.

See [Project Auth](https://docs.routebase.dev/project-auth/) for the editor and the token manager.

## Frequently asked questions

### What is OAuth 2.0?

OAuth 2.0, defined in RFC 6749, is a framework for delegated access. It lets an application obtain a token to act on a resource owner's behalf without ever seeing that owner's password. The framework defines several flows, called grants, and choosing the right one for your client type is most of what using OAuth well consists of.

### Which OAuth 2.0 grant type should I use?

Use client credentials when a machine calls on its own behalf with no user involved. Use authorization code with PKCE whenever a user is delegating access, regardless of whether the client is a web application, a mobile app or a single-page application. The implicit grant and the resource owner password credentials grant are both retired by RFC 9700 and should not be used in new work.

### What is PKCE and why is it required?

Proof Key for Code Exchange, defined in RFC 7636, binds an authorization code to the client that requested it. The client sends a hash of a random secret when it starts the flow and the secret itself when it redeems the code, so a code intercepted in transit is useless to anyone else. RFC 9700 extends the requirement from public clients to every authorization code flow, because the protection costs nothing and closes a real interception path.

### Why was the OAuth implicit grant deprecated?

It returned the access token directly in the URL fragment of a redirect, which exposed it to the browser history, to any script on the page and to referrer leakage. There was also no way to authenticate the client. Authorization code with PKCE achieves the same outcome for browser-based applications without those exposures. RFC 9700 states that the implicit grant should no longer be used.

---

[Routebase](https://routebase.dev/) — [Sign up](https://app.routebase.dev/): Every account starts with a 14-day Pro trial — no credit card required.
