Authorization Code vs Client Credentials — When to Use Each
The most common OAuth mistake is using the wrong grant type. Authorization Code + PKCE is for when a user is present and authorizing your app. Client Credentials is for server-to-server calls with no user involved.
Authorization Code + PKCE — user present
Use this when a human user needs to grant your app access to their account on another service.
- User is redirected to the auth server to log in
- User sees a consent screen and approves access
- Auth server redirects back with an authorization code
- Your app exchanges the code for tokens
// Typical use cases: // - "Sign in with Google" // - "Connect your Slack workspace" // - "Allow access to your GitHub repos" // - Any flow where the user must approve access
Client Credentials — no user, machine-to-machine
Use this for server-to-server API calls where there is no user involved. Your server authenticates directly with the auth server using its own credentials.
- No redirect, no user interaction
- Your server sends client_id and client_secret directly
- Gets an access token for making API calls
// POST directly to the token endpoint
const response = await fetch('https://auth.example.com/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
scope: 'read:data write:data',
})
});
// Use the access token for API calls
const { access_token } = await response.json();
Other flows and when they apply
| Flow | When to use |
|---|---|
| Authorization Code + PKCE | SPAs, mobile apps, any user-facing flow |
| Client Credentials | Server-to-server, background jobs, microservices |
| Device Code | TVs, CLI tools, devices with no browser |
| Refresh Token | Not a standalone flow — used with Authorization Code to get new access tokens |
Never use Implicit Flow
Implicit Flow (response_type=token) was deprecated in OAuth 2.1. It returns tokens in the URL fragment — which gets logged in browser history, server logs, and can be stolen by referrer headers. Always use Authorization Code + PKCE for SPAs instead.
Debug your OAuth errors → OAuthFixer