This document explains the OAuth2 flows supported by AuthMaster.
The most common OAuth2 flow for web and mobile applications.
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
First, register your application to get credentials:
curl -X POST https://api.auth.example.com/api/v1/apps/register \
-H "Authorization: Bearer YOUR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My App",
"description": "My application description",
"redirect_uris": ["https://myapp.com/callback"],
"scopes": ["openid", "profile", "email"]
}'Save the app_id and app_secret from the response.
Redirect the user to the authorization endpoint:
https://auth.example.com/oauth2/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://myapp.com/callback&
scope=openid+profile+email&
state=RANDOM_STATE&
code_challenge=CODE_CHALLENGE&
code_challenge_method=S256
Parameters:
response_type: Must becodeclient_id: Your application's client IDredirect_uri: Callback URL (must match registered URI)scope: Space-separated list of requested scopesstate: Random string to prevent CSRF attackscode_challenge: PKCE challenge (optional but recommended)code_challenge_method: PKCE method (S256orplain)
The user will be presented with a login page and consent screen. After authorizing, they will be redirected to:
https://myapp.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE
Exchange the authorization code for an access token:
curl -X POST https://api.auth.example.com/oauth2/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "AUTHORIZATION_CODE",
"redirect_uri": "https://myapp.com/callback",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"code_verifier": "CODE_VERIFIER"
}'Response:
{
"access_token": "ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "REFRESH_TOKEN",
"scope": "openid profile email"
}Use the access token to access protected resources:
curl https://api.auth.example.com/oauth2/userinfo \
-H "Authorization: Bearer ACCESS_TOKEN"Response:
{
"sub": "user-id",
"email": "user@example.com",
"email_verified": true
}Used for machine-to-machine authentication.
+----------+ +---------------+
| | | |
| Client |----(A)- Client Credentials ----->| Authorization |
| | | Server |
| |<---(B)---- Access Token ---------| |
| | | |
+----------+ +---------------+
Request an access token using client credentials:
curl -X POST https://api.auth.example.com/oauth2/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}'Response:
{
"access_token": "ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 3600
}Used to obtain a new access token using a refresh token.
curl -X POST https://api.auth.example.com/oauth2/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"refresh_token": "REFRESH_TOKEN",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}'Response:
{
"access_token": "NEW_ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "NEW_REFRESH_TOKEN",
"scope": "openid profile email"
}PKCE adds an extra layer of security to the authorization code flow. It's highly recommended for public clients (mobile apps, SPAs).
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64URLEncode(array);
}async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const hash = await crypto.subtle.digest('SHA-256', data);
return base64URLEncode(new Uint8Array(hash));
}- Generate a code verifier and challenge before redirecting
- Store the verifier securely (e.g., sessionStorage)
- Include
code_challengeandcode_challenge_method=S256in authorization request - Include
code_verifierwhen exchanging the code for tokens
Available scopes:
openid- Required for OpenID Connectprofile- Access to user profile informationemail- Access to user email addressread- Read access to user datawrite- Write access to user data
- Access tokens: 1 hour
- Refresh tokens: 30 days
- Authorization codes: 10 minutes
- Always use HTTPS in production
- Validate redirect URIs - Only redirect to registered URIs
- Use PKCE - Especially for public clients
- Implement state parameter - Prevent CSRF attacks
- Store secrets securely - Never expose client secrets in frontend code
- Validate tokens - Verify token signatures and expiration
- Use short-lived tokens - Implement token refresh
- Implement rate limiting - Prevent abuse
- Log security events - Monitor for suspicious activity
- Keep dependencies updated - Patch security vulnerabilities
Common OAuth2 errors:
invalid_request- Malformed requestunauthorized_client- Client not authorized for this grant typeaccess_denied- User denied authorizationunsupported_response_type- Invalid response typeinvalid_scope- Invalid or unsupported scopeserver_error- Internal server errortemporarily_unavailable- Server temporarily unavailable
// 1. Generate PKCE values
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
// 2. Store verifier
sessionStorage.setItem('code_verifier', codeVerifier);
// 3. Redirect to authorization
const params = new URLSearchParams({
response_type: 'code',
client_id: 'YOUR_CLIENT_ID',
redirect_uri: 'https://myapp.com/callback',
scope: 'openid profile email',
state: generateRandomState(),
code_challenge: codeChallenge,
code_challenge_method: 'S256'
});
window.location.href = `https://auth.example.com/oauth2/authorize?${params}`;
// 4. Handle callback
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const verifier = sessionStorage.getItem('code_verifier');
// 5. Exchange code for tokens
const response = await fetch('https://api.auth.example.com/oauth2/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
code,
redirect_uri: 'https://myapp.com/callback',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
code_verifier: verifier
})
});
const tokens = await response.json();import requests
import secrets
import hashlib
import base64
# 1. Generate PKCE values
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')
# 2. Build authorization URL
auth_url = 'https://auth.example.com/oauth2/authorize'
params = {
'response_type': 'code',
'client_id': 'YOUR_CLIENT_ID',
'redirect_uri': 'https://myapp.com/callback',
'scope': 'openid profile email',
'state': secrets.token_urlsafe(32),
'code_challenge': code_challenge,
'code_challenge_method': 'S256'
}
# 3. Exchange code for tokens
token_response = requests.post(
'https://api.auth.example.com/oauth2/token',
json={
'grant_type': 'authorization_code',
'code': authorization_code,
'redirect_uri': 'https://myapp.com/callback',
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET',
'code_verifier': code_verifier
}
)
tokens = token_response.json()Use the OpenID Connect Discovery endpoint to test your integration:
curl https://api.auth.example.com/.well-known/openid-configurationThis returns all available endpoints and supported features.