#2. OAuth 2.0 Implementation
Connected Services Framework (CSF) — Part 2: Implementation — Version 2.0
#2.1 Overview
The CSF uses OAuth 2.0 Client Credentials flow for machine-to-machine authentication between MAPs. This is the same approach used by TOTSCo for OTS, ensuring maximum compatibility across the industry.
Each MAP operates as both:
- An OAuth 2.0 Authorisation Server — issuing tokens to other MAPs that want to access its endpoints
- An OAuth 2.0 Client — requesting tokens from other MAPs to access their endpoints
During onboarding, MAPs exchange client_id and client_secret credentials with each other.
#2.2 Access Token Request
To obtain an access token, the requesting MAP sends an HTTP POST to the target MAP's token endpoint.
Request URL: https://{fqdn}/oauth2/token
The FQDN is obtained from the oauthTokenURL field in the target MAP's registry (see Directory API).
#Request Headers
| Header | Value | Notes |
|---|---|---|
Authorization | Basic <Base64(client_id:client_secret)> | Base64-encoded credentials provided during onboarding |
Content-Type | application/x-www-form-urlencoded | Standard OAuth 2.0 form encoding |
#Request Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
grant_type | String | yes | always client_credentials |
client_id | String | Yes | Client identifier provided by the target MAP during onboarding |
client_secret | String | Yes | Client secret provided by the target MAP during onboarding |
Note : A MAP should support client_id + client_secret in both headers and body as per OAuth 2.0 Standard
#2.3 Access Token Response
A successful request returns an HTTP 200 with the following JSON body:
{
"access_token": "{OAuth2 Access Token}",
"token_type": "bearer",
"scope": "default",
"expires_in": 3600
}
| Field | Type | Mandatory | Default | Description |
|---|---|---|---|---|
access_token | String | Y | — | The bearer token to include in subsequent API requests |
token_type | String | Y | bearer | The type of token issued |
scope | String | N | default | The scope of access granted |
expires_in | Integer | Y | 3600 | Token validity in seconds (typically 1 hour) |
#2.4 Using the Access Token
Include the access token in the Authorization header of all API requests:
Authorization: Bearer {access_token}
The token MUST be validated by the receiving MAP on every request, checking:
- Token signature validity
- Token has not expired
- Issuer matches the expected authorisation server
- Audience/scope is appropriate for the requested resource
#2.5 Token Lifecycle
- Tokens are short-lived (typically 1 hour)
- MAPs SHOULD cache tokens and reuse them until close to expiry
- Client secrets MUST be stored securely (e.g., in environment variables or secret vaults, never in source code)
- Client secrets SHOULD be rotated periodically
#2.6 Error Responses
The following errors may be returned during token generation:
| HTTP Code | Error | Root Cause |
|---|---|---|
| 400 | Bad Request | Invalid request parameters or missing required fields |
| 401 | Unauthorised | Incorrect client credentials (client_id or client_secret) |
| 404 | Not Found | Incorrect token generation URL |
| 405 | Method Not Allowed | Incorrect HTTP method (must be POST) |
| 415 | Unsupported Media Type | Missing or incorrect Content-Type header |
#2.7 Security Requirements
| Requirement | Mandatory |
|---|---|
| All token exchanges over TLS 1.3 | Yes |
| Validate token signature, issuer, and audience on every request | Yes |
| Limit token scope and lifetime | Yes |
| Never expose client secrets in frontend code or logs | Yes |
| Store client secrets in secure vaults or environment variables | Yes |
| Rotate client secrets periodically | Recommended |
| Use Proof Key for Code Exchange (PKCE) for public clients | If applicable |