OAuth 2.0 Flow Selection: Authorization Code vs Client Credentials
Choose OAuth 2.0 Authorization Code Flow for user data and Client Credentials Flow for machine-to-machine access.
02 Aug 2025, 17:07 UTC

Decision: match the flow to the resource owner
Pick Authorization Code Flow when a human user owns the data and your application must act on that user's behalf without seeing their password. Pick Client Credentials Flow when the application itself owns the resource or has system-level permissions, such as a background job calling an internal API.
Use this constraint checklist before choosing:
- Does a human user need to sign in and consent?
- Can the client store a secret where users cannot read it?
- Is the token for a user's data or for application-level data?
Supported options compared
| Factor | Authorization Code Flow | Client Credentials Flow |
|---|---|---|
| Resource owner | Human user | Client application or system |
| User interaction | Browser redirect and consent screen | None |
| Client secret | Required for confidential clients | Required |
| Public clients (SPA, mobile) | Allowed with PKCE | Not appropriate |
| Refresh tokens | Typically issued | Rarely issued |
| Token endpoint grant_type | authorization_code | client_credentials |
Trade-offs
Authorization Code Flow
Use this flow for user-facing applications. The authorization server redirects the user's browser back to your registered redirect URI with an authorization code. Your server exchanges that code for tokens. Because the code alone is not enough, add Proof Key for Code Exchange (PKCE) when the client cannot securely store a secret, such as a single-page app or mobile app. PKCE prevents authorization code injection by binding the code request to a code verifier generated by the client.
Refresh tokens let your application obtain new access tokens without asking the user to sign in again. Store refresh tokens securely and rotate them where the authorization server supports it.
Client Credentials Flow
Use this flow for machine-to-machine communication. The client sends its credentials directly to the token endpoint and receives an access token. There is no user, no consent screen, and no redirect URI. The token's subject typically identifies the client, not a person.
Never use this flow on behalf of a user. It cannot represent delegated user permissions, and most authorization servers do not issue refresh tokens for it.
Implementation and validation
Run the following requests from a terminal, CI job, or administrative host that can reach the authorization server's token endpoint. Replace every placeholder in angle brackets with values from your authorization server client registration.
Client Credentials Flow request
curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=" \
-d "client_secret=" \
-d "scope="
Where to run: any host with network access to the token endpoint. Permissions: none beyond network access and knowledge of the client secret. Risk: the secret can appear in shell history and process lists unless you clear history or use a secrets manager. Expected check: HTTP 200 with a JSON body containing access_token, token_type, and expires_in.
Authorization Code Flow token exchange
curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=" \
-d "redirect_uri=" \
-d "client_id=" \
-d "client_secret="
Where to run: your application server after receiving the redirect from the authorization server. Permissions: access to the authorization code and client secret. Risk: an intercepted authorization code can be exchanged if PKCE is not enforced, so always require code_verifier for public clients and validate the redirect URI against your registered list.
Validate the issued token
Decode the access token, often a JWT, and inspect its claims. Do not rely on the token string alone.
- For Authorization Code Flow, the
subclaim, which identifies the subject, should identify the end user. - For Client Credentials Flow, the
subclaim should identify the client ID or a service account. - The
audclaim, which identifies the intended audience, should match your resource server's expected audience.
Use your language's JWT library or a command-line JWT tool to inspect claims locally. A mismatched sub or missing aud means the token was issued for the wrong principal or audience.
Limitations
- Client Credentials Flow cannot act on behalf of a specific user. If your API requires user-level authorization, use Authorization Code Flow.
- Authorization Code Flow requires a browser-capable user agent for the initial consent step. Headless scripts cannot complete it without a separate device-flow or token-exchange extension, which is outside this guide.
- Short-lived access tokens reduce theft impact but increase refresh-token traffic. Monitor token issuance rates to avoid hitting authorization server limits.
Practical verification
- Register a test client in your authorization server with a known redirect URI.
- Request a token using Client Credentials Flow and confirm the response contains an access token.
- Call your resource server with that token in an
Authorization: Bearerheader and confirm access is granted or denied based on the client's scopes. - Repeat with Authorization Code Flow using a test user account and confirm the
subclaim matches the user, not the client.
If the token endpoint rejects an unregistered redirect URI, your authorization server is enforcing allow-listing, which is the expected behavior. If it accepts any URI, review the client configuration before deploying to production.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.