OAuth 2.0 Grant Types
The grant_types attribute specifies which OAuth 2.0 flows (authorization grants) the client is permitted to use.
Standard Grant Types (RFC 6749)
authorization_code
The most common and secure flow
- User redirected to authorization server for authentication and consent
- Authorization server returns authorization code to client’s redirect URI
- Client exchanges code for tokens at token endpoint
- Supports refresh tokens
- Tokens never exposed to browser
- Works with PKCE for public clients
sequenceDiagram
participant User
participant Client
participant AuthServer as Authorization Server
participant API as Resource Server
User->>Client: 1. Click "Login"
Client->>AuthServer: 2. Redirect to /authorize
Note over AuthServer: response_type=code
User->>AuthServer: 3. Authenticate & consent
AuthServer->>Client: 4. Redirect with code
Note over Client: https://app.com/callback?code=ABC123
Client->>AuthServer: 5. POST /token (exchange code)
Note over Client,AuthServer: Code + client credentials
AuthServer->>Client: 6. Return tokens
Note over Client: access_token, refresh_token, id_token
Client->>API: 7. Call API with access_token
Note over Client,API: Authorization: Bearer {token}
API->>Client: 8. Protected resource
Flow:
- Client redirects user to authorization endpoint
- User authenticates and grants consent
- Authorization server redirects back with code
- Client exchanges code for access token (and optionally refresh token)
Best for:
- Web applications (confidential clients)
- Single Page Applications with PKCE
- Mobile applications with PKCE
- Native applications with PKCE
Example Registration:
{
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"]
}
implicit
⚠️ DEPRECATED - Do not use
- Tokens returned directly in redirect URI fragment (no code exchange)
- Access token exposed in browser history and logs
- No refresh tokens
- No client authentication
- Originally designed for SPAs before PKCE existed
sequenceDiagram
participant User
participant Client
participant AuthServer as Authorization Server
participant API as Resource Server
User->>Client: 1. Click "Login"
Client->>AuthServer: 2. Redirect to /authorize
Note over AuthServer: response_type=token
User->>AuthServer: 3. Authenticate & consent
AuthServer->>Client: 4. Redirect with tokens in URL fragment
Note over Client: https://app.com/callback#access_token=XYZ789
Note over Client: ⚠️ Token exposed in browser!
rect rgb(255, 200, 200)
Note over Client: No token endpoint exchange
Note over Client: No client authentication
Note over Client: No refresh token
end
Client->>API: 5. Call API with access_token
Note over Client,API: Authorization: Bearer {token}
API->>Client: 6. Protected resource
Status: Removed in OAuth 2.1 specification
Migration: Use authorization_code with PKCE instead
password (Resource Owner Password Credentials)
⚠️ Use with extreme caution
- User provides username and password directly to client application
- Client sends credentials to token endpoint
- Token endpoint returns access token (and optionally refresh token)
- Bypasses authorization server’s login page
- No interactive consent
sequenceDiagram
participant User
participant Client
participant AuthServer as Authorization Server
participant API as Resource Server
User->>Client: 1. Enter username & password
Note over User,Client: User enters credentials in client app
Client->>AuthServer: 2. POST /token
Note over Client,AuthServer: grant_type=password
username=johndoe
password=***
client_id=xyz
rect rgb(255, 240, 200)
Note over AuthServer: ⚠️ Client handles user credentials directly
Note over AuthServer: Only for trusted first-party apps!
end
AuthServer->>Client: 3. Return tokens
Note over Client: access_token, refresh_token
Client->>API: 4. Call API with access_token
Note over Client,API: Authorization: Bearer {token}
API->>Client: 5. Protected resource
When to use:
- ✅ Highly trusted first-party applications only
- ✅ Migration path from legacy authentication
- ❌ Never for third-party applications
- ❌ Avoid if
authorization_codeflow is possible
Example Request:
POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=password
&username=johndoe
&password=A3ddj3w
&client_id=s6BhdRkqt3
Example Registration:
{
"grant_types": ["password", "refresh_token"],
"response_types": []
}
client_credentials
Machine-to-machine authentication
- No user context - client acts on its own behalf
- Client exchanges its own credentials for access token
- Used for service-to-service communication
- No refresh tokens (just request new access token when needed)
- No authorization code or redirect
sequenceDiagram
participant Client as Client Service
participant AuthServer as Authorization Server
participant API as Resource Server
Note over Client: No user involved
Client->>AuthServer: 1. POST /token
Note over Client,AuthServer: grant_type=client_credentials
client_id=service123
client_secret=***
scope=api:read api:write
AuthServer->>AuthServer: 2. Verify client credentials
AuthServer->>Client: 3. Return access_token
Note over Client: access_token only
(no refresh_token)
Client->>API: 4. Call API with access_token
Note over Client,API: Authorization: Bearer {token}
API->>Client: 5. Protected resource
Note over Client: When token expires,
request new token
Flow:
- Client authenticates directly at token endpoint
- Token endpoint returns access token
- Client uses access token to call APIs
Best for:
- Backend services
- API-to-API communication
- Batch jobs
- Daemon processes
- Service accounts
Example Request:
POST /token HTTP/1.1
Host: authorization-server.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&scope=api:read api:write
Example Registration:
{
"grant_types": ["client_credentials"],
"response_types": [],
"token_endpoint_auth_method": "private_key_jwt"
}
refresh_token
Exchange refresh token for new access token
- Not a standalone flow - used with other grant types
- Allows obtaining new access tokens without re-authentication
- Must be explicitly requested in scope or grant_types
- Enables long-lived sessions
- Can be revoked by authorization server
sequenceDiagram
participant Client
participant AuthServer as Authorization Server
participant API as Resource Server
Note over Client: Client previously obtained
refresh_token from authorization_code
or password grant
Client->>API: 1. Call API with access_token
API->>Client: 2. 401 Unauthorized (token expired)
Client->>AuthServer: 3. POST /token (refresh)
Note over Client,AuthServer: grant_type=refresh_token
refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
client_id=xyz
AuthServer->>AuthServer: 4. Validate refresh_token
AuthServer->>Client: 5. Return new tokens
Note over Client: New access_token
Optionally: new refresh_token
Client->>API: 6. Retry API call with new access_token
Note over Client,API: Authorization: Bearer {new_token}
API->>Client: 7. Protected resource
Flow:
- Client receives refresh token from initial authorization
- When access token expires, client uses refresh token at token endpoint
- Token endpoint returns new access token (and optionally new refresh token)
Example Request:
POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
&client_id=s6BhdRkqt3
Supported with:
- ✅
authorization_code - ✅
password - ❌
implicit(implicit never provides refresh tokens) - ❌
client_credentials(just request new access token)
Extended Grant Types
urn:ietf:params:oauth:grant-type:jwt-bearer (RFC 7523)
JWT Bearer Token Flow
- Exchange a JWT for an access token
- JWT can be self-issued or from another authorization server
- Used for federation and delegation scenarios
- Common in enterprise identity systems
sequenceDiagram
participant Client as Client/Service
participant IDP as Identity Provider
participant AuthServer as Authorization Server
participant API as Resource Server
Note over Client: Scenario: Service wants to act
on behalf of user from another IDP
Client->>IDP: 1. Obtain JWT assertion
Note over IDP: User authenticated here
IDP->>Client: 2. Return signed JWT
Note over Client: JWT contains subject (user),
issuer, audience, expiry
Client->>AuthServer: 3. POST /token
Note over Client,AuthServer: grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6IjE2In0...
AuthServer->>AuthServer: 4. Validate JWT signature & claims
Note over AuthServer: Verify issuer, audience,
expiry, signature
AuthServer->>Client: 5. Return access_token
Client->>API: 6. Call API with access_token
Note over Client,API: Authorization: Bearer {token}
API->>Client: 7. Protected resource
Use cases:
- Service account impersonation
- Cross-domain authentication
- Token exchange between systems
Example Request:
POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6IjE2In0...
urn:ietf:params:oauth:grant-type:saml2-bearer (RFC 7522)
SAML 2.0 Bearer Assertion Flow
- Exchange a SAML 2.0 assertion for an access token
- Used for SAML-to-OAuth bridging
- Common in enterprise identity federation
- Allows SAML-based systems to access OAuth-protected APIs
sequenceDiagram
participant User
participant Client
participant SAML_IDP as SAML Identity Provider
participant AuthServer as Authorization Server
participant API as Resource Server
User->>Client: 1. Access application
Client->>SAML_IDP: 2. SAML authentication request
User->>SAML_IDP: 3. Authenticate
SAML_IDP->>Client: 4. SAML assertion (XML)
Note over Client: SAML assertion contains
user identity & attributes
Client->>AuthServer: 5. POST /token
Note over Client,AuthServer: grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer
assertion=[base64-encoded-SAML]
AuthServer->>AuthServer: 6. Validate SAML assertion
Note over AuthServer: Verify signature, issuer,
audience, conditions
AuthServer->>Client: 7. Return access_token
Client->>API: 8. Call API with access_token
Note over Client,API: Authorization: Bearer {token}
API->>Client: 9. Protected resource
Use cases:
- Enterprise SSO integration
- Legacy SAML systems accessing modern APIs
- Federation across identity providers
urn:ietf:params:oauth:grant-type:device_code (RFC 8628)
Device Authorization Flow
- For input-constrained devices (smart TVs, IoT devices, CLI tools)
- Device displays a user code
- User enters code on another device (phone, computer)
- Device polls token endpoint until user completes authorization
sequenceDiagram
participant Device as Smart TV/IoT Device
participant AuthServer as Authorization Server
participant User
participant Browser as User's Browser/Phone
participant API as Resource Server
Device->>AuthServer: 1. POST /device_authorization
Note over Device,AuthServer: client_id=device123
AuthServer->>Device: 2. Return device_code & user_code
Note over Device: device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
user_code=WDJB-MJHT
verification_uri=https://example.com/device
Device->>User: 3. Display user_code & URL
Note over Device,User: "Visit example.com/device
Enter code: WDJB-MJHT"
User->>Browser: 4. Open verification_uri
Browser->>AuthServer: 5. GET /device
User->>Browser: 6. Enter user_code
Browser->>AuthServer: 7. Submit code
User->>Browser: 8. Authenticate & consent
loop Poll every 5 seconds
Device->>AuthServer: 9. POST /token (poll)
Note over Device,AuthServer: grant_type=urn:ietf:params:oauth:grant-type:device_code
device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
AuthServer->>Device: 10a. authorization_pending (keep polling)
end
AuthServer->>Device: 10b. Return tokens
Note over Device: access_token, refresh_token
Device->>API: 11. Call API with access_token
API->>Device: 12. Protected resource
Flow:
- Device requests device code from authorization server
- Device displays user code and verification URL
- User visits URL on another device and enters code
- Device polls token endpoint
- Once user approves, device receives access token
Best for:
- Smart TVs
- IoT devices
- Command-line tools
- Devices without browsers
Example Registration:
{
"grant_types": [
"urn:ietf:params:oauth:grant-type:device_code",
"refresh_token"
],
"response_types": []
}
urn:ietf:params:oauth:grant-type:token-exchange (RFC 8693)
Token Exchange Flow
- Exchange one token for another
- Supports impersonation and delegation
- Used for microservices calling other services on behalf of user
- Supports actor tokens for complex delegation chains
sequenceDiagram
participant User
participant ServiceA as Service A (Frontend)
participant AuthServer as Authorization Server
participant ServiceB as Service B (Backend)
participant ServiceC as Service C (Data Layer)
User->>ServiceA: 1. Request with access_token
Note over ServiceA: Token has broad permissions
ServiceA->>AuthServer: 2. POST /token (exchange)
Note over ServiceA,AuthServer: grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=original_access_token
subject_token_type=urn:ietf:params:oauth:token-type:access_token
scope=serviceB:read (downscoped)
AuthServer->>AuthServer: 3. Validate & create new token
Note over AuthServer: New token has reduced scope
for ServiceB only
AuthServer->>ServiceA: 4. Return new access_token
Note over ServiceA: Token scoped for ServiceB
ServiceA->>ServiceB: 5. Call ServiceB with new token
Note over ServiceA,ServiceB: Authorization: Bearer {downscoped_token}
ServiceB->>AuthServer: 6. POST /token (exchange again)
Note over ServiceB,AuthServer: actor_token=serviceB_token
subject_token=downscoped_token
scope=serviceC:write
AuthServer->>ServiceB: 7. Return token with actor chain
ServiceB->>ServiceC: 8. Call ServiceC
Note over ServiceB,ServiceC: Token shows: User -> ServiceA -> ServiceB
ServiceC->>ServiceB: 9. Response
ServiceB->>ServiceA: 10. Response
ServiceA->>User: 11. Final response
Use cases:
- Microservice architecture (service A calls service B on behalf of user)
- Token downscoping (reduce scope/permissions)
- Token type conversion (JWT to opaque, etc.)
Example Request:
POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=accVkjcJyb4BWCxGsndESCJQbdFMogUC5PbRDqceLTC
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&scope=api:read
Grant Type Comparison
| Grant Type | User Context | Redirect | Use Case | Security |
|---|---|---|---|---|
authorization_code | ✅ Yes | ✅ Yes | Web/mobile apps | 🔒🔒🔒🔒🔒 |
implicit | ✅ Yes | ✅ Yes | DEPRECATED | ❌ |
password | ✅ Yes | ❌ No | Trusted first-party only | 🔒🔒 |
client_credentials | ❌ No | ❌ No | Service accounts | 🔒🔒🔒🔒 |
refresh_token | ✅ Yes | ❌ No | Token refresh | 🔒🔒🔒🔒 |
device_code | ✅ Yes | ❌ No | Input-limited devices | 🔒🔒🔒🔒 |
Typical Combinations
Web Application (Confidential Client)
{
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "private_key_jwt"
}
Single Page Application (Public Client)
{
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}
Note: Must use PKCE
Mobile/Native Application (Public Client)
{
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}
Note: Must use PKCE and platform-specific best practices
Backend Service/API (Confidential Client)
{
"grant_types": ["client_credentials"],
"response_types": [],
"token_endpoint_auth_method": "private_key_jwt"
}
IoT/Smart TV Device
{
"grant_types": [
"urn:ietf:params:oauth:grant-type:device_code",
"refresh_token"
],
"response_types": [],
"token_endpoint_auth_method": "none"
}
Legacy First-Party App (Migration Scenario)
{
"grant_types": ["password", "refresh_token"],
"response_types": [],
"token_endpoint_auth_method": "client_secret_basic"
}
Note: Migrate to authorization_code as soon as possible
Security Recommendations
✅ Recommended
- Use
authorization_codefor all user-facing applications - Use PKCE with
authorization_codefor public clients - Use
client_credentialsfor service accounts - Use
refresh_tokenwhen long-lived sessions are needed - Use
device_codefor input-constrained devices
⚠️ Use with Caution
password- Only for highly trusted first-party applications- Migration scenarios only
- Consider
authorization_codeinstead
❌ Do Not Use
implicit- Deprecated in OAuth 2.1- Replaced by
authorization_codewith PKCE - No security benefits, multiple vulnerabilities