Authorization Code Grant
For the authorization code grant flow we require PKCE (Proof Key for Code Exchange).
Overview with of Authorization code grant with PKCE (Proof Key for Code Exchange)
A highly secure flow in the OAuth 2.0 framework. It enhances the standard Authorization Code flow, primarily to protect public clients (like mobile and single-page applications) that cannot securely store a client_secret
Use Cases:
- Native Mobile Applications: Clients (iOS, Android apps) that cannot securely store a traditional, static client_secret within their distributed code.
- Single-Page Applications (SPAs): Client-side JavaScript applications running in a browser that are vulnerable to code inspection, making them unable to secure a static client_secret.
- Desktop Applications: Applications running on an end-user's machine, which are also considered public clients for security purposes.
- Confidential Clients (Web Apps with a Backend): Although they can use a client_secret, PKCE is still recommended as an extra layer of defense against certain types of code injection and CSRF attacks.
Key Benefits:
- Prevents Code Interception Attacks An attacker who intercepts the authorization_code from the redirect URI cannot exchange it for an access token because they do not possess the secret code_verifier. This is the primary security benefit.
- Eliminates Client Secret for Public Clients PKCE removes the need for public clients (like SPAs and Mobile apps) to register or use a static client_secret, solving the problem of insecure secret storage.
- Mitigates Cross-Site Request Forgery (CSRF) By dynamically linking the initial authorization request to the final token exchange, PKCE provides strong protection against CSRF, often making the use of the state parameter redundant for this specific purpose.
- Default Security Standard PKCE is now mandated in the OAuth 2.0 Security Best Current Practice and the upcoming OAuth 2.1 specification, making it the required flow for modern application development.
Authorization Code Flow with PKCE
Flow Steps in Detail
Step 1: Authorization Request
The client application redirects the user to the authorization endpoint with the following parameters:
Request:
GET /w/{tenant}/oauth/api/v1/authorize?
response_type=code&
client_id=your-client-id&
redirect_uri=https://yourapp.com/callback&
scope=openid+profile+email+patient/*.read&
state=random-state-value&
code_challenge=CHALLENGE&
code_challenge_method=S256 HTTP/1.1
Host: api.haste.health
Parameters:
| Parameter | Required | Description |
|---|---|---|
response_type | Yes | Must be code for authorization code flow |
client_id | Yes | Your application's client identifier |
redirect_uri | Yes | Where to redirect after authorization (must be pre-registered) |
scope | Yes | Space-delimited list of requested scopes (must include openid for OIDC) |
state | Recommended | Random value to prevent CSRF attacks |
code_challenge | Required | PKCE code challenge (SHA-256 hash of code_verifier) |
code_challenge_method | Required | Must be S256 (SHA-256 hash method) |
nonce | Optional | Random value included in ID token to prevent replay attacks |
prompt | Optional | none, login, consent, or select_account |
max_age | Optional | Maximum authentication age in seconds |
Step 2: User Authentication
The authorization server authenticates the user through:
- Login form (username/password, MFA)
- Session cookie (if already logged in)
- Federated identity provider (SSO)
Step 3: User Consent
If required, the authorization server displays a consent screen showing:
- Application name and description
- Requested scopes and permissions
- Option to approve or deny
Step 4: Authorization Code Generation
Upon successful authentication and consent, the authorization server:
- Generates a short-lived authorization code (typically 1-10 minutes)
- Associates the code with the client, user, and requested scopes
- Redirects back to the client's redirect URI
Response:
HTTP/1.1 302 Found
Location: https://yourapp.com/callback?
code=AUTH_CODE_HERE&
state=random-state-value
Step 5: Token Exchange
The SPA exchanges the authorization code for tokens using the code_verifier (no client_secret needed for public clients):
Request:
POST /w/{tenant}/oauth/api/v1/token HTTP/1.1
Host: api.haste.health
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTH_CODE_HERE&
redirect_uri=https://yourapp.com/callback&
client_id=spa-client-id&
code_verifier=ORIGINAL_VERIFIER
Parameters:
| Parameter | Required | Description |
|---|---|---|
grant_type | Yes | Must be authorization_code |
code | Yes | The authorization code received from callback |
redirect_uri | Yes | Must exactly match the original redirect URI |
client_id | Yes | Your SPA's registered client identifier |
code_verifier | Required | The original random string used to generate code_challenge (retrieved from sessionStorage) |
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"scope": "openid profile email patient/*.read",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Step 6: Access Protected Resources
Use the access token to call protected APIs:
Request:
GET /w/{tenant}/{project}/api/v1/fhir/r4/Patient/123 HTTP/1.1
Host: api.haste.health
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Error Handling
Authorization Errors
| Error Code | Description | Resolution |
|---|---|---|
invalid_request | Missing or invalid required parameter | Check all required parameters are included |
unauthorized_client | Client not authorized for this grant type | Verify client configuration |
access_denied | User denied authorization request | Inform user and allow retry |
unsupported_response_type | Authorization server doesn't support response type | Use response_type=code |
invalid_scope | Requested scope is invalid or unknown | Check scope names and permissions |
server_error | Authorization server error | Retry with exponential backoff |
temporarily_unavailable | Server temporarily unavailable | Retry after delay |
Token Exchange Errors
| Error Code | Description | Resolution |
|---|---|---|
invalid_request | Missing required parameter | Include all required parameters |
invalid_client | Client authentication failed | Verify client_id and client_secret |
invalid_grant | Authorization code invalid, expired, or revoked | Request new authorization |
unauthorized_client | Client not authorized for authorization code grant | Update client configuration |
unsupported_grant_type | Grant type not supported | Use grant_type=authorization_code |
Example Error Response
{
"error": "invalid_grant",
"error_description": "The authorization code has expired or has already been used",
"error_uri": "https://api.haste.health/errors/invalid_grant"
}
Comparison with Other Flows
| Feature | Authorization Code + PKCE | Client Credentials | Implicit (Deprecated) |
|---|---|---|---|
| Use Case | SPAs, mobile apps | Service-to-service | SPAs (legacy) |
| Client Secret | Not required (PKCE) | Required | Not possible |
| Refresh Tokens | Yes | Optional | No |
| Security | Highest | High | Low |
| User Context | Yes | No | Yes |
| PKCE Required | ✅ Yes | ❌ No | N/A |
| Recommended | ✅ Yes | ✅ Yes | ❌ No (use Auth Code + PKCE) |