Machine-to-Machine Authentication This endpoint allows you to obtain a Bearer token for machine-to-machine authentication with the ESFA Backend API. The Authentication Service is a separate service from the Backend API.
Endpoint Details URL: POST /v1/oauth/token/machineService: Authentication Service (separate from Backend API) Content-Type: application/json
Note : This endpoint is hosted by the Authentication Service, not the Backend API. The base URL will be different from your Backend API base URL.
Request
Content-Type: application/json
Request Body Field
Type
Required
Description
apiKey
string
Yes
Your API key provided by the administrator
secretKey
string
Yes
Your secret key provided by the administrator
Example Request
{
"apiKey": "your-api-key-here",
"secretKey": "your-secret-key-here"
}
cURL Example
curl -X POST https://auth.your-service.tld/v1/oauth/token/machine \
-H "Content-Type: application/json" \
-d '{
"apiKey": "your-api-key-here",
"secretKey": "your-secret-key-here"
}'
Response Success Response (200 OK)
{
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires": "2025-09-05T13:31:23.174Z"
}
}
Response Fields Field
Type
Description
data.token
string
JWT Bearer token for API authentication
data.expires
string
ISO 8601 timestamp when the token expires (UTC)
Token Usage Use the returned token in subsequent Backend API calls:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Error Responses 400 Bad Request Invalid request payload or malformed JSON.
{
"errors": [
{
"i18N": "INVALID_REQUEST",
"error": "Bad request - invalid input",
"type": "BadRequest"
}
]
}
Common causes:
401 Unauthorized Invalid API credentials.
{
"errors": [
{
"i18N": "INVALID_CREDENTIALS",
"error": "Invalid API key or secret key",
"type": "Unauthorized"
}
]
}
Common causes:
500 Internal Server Error Temporary server issue.
{
"errors": [
{
"i18N": "SERVER_ERROR",
"error": "Internal server error",
"type": "ServerError"
}
]
}
Recommended action: Retry the request after a brief delay with exponential backoff.
Token Management Token Lifetime Tokens are short-lived for security
Typical lifetime: 15 minutes to 1 hour (configured by service)
Check the expires field for exact expiration time
Token Refresh Tokens cannot be refreshed - you must request a new token
Implement automatic refresh when you receive 401 Unauthorized from Backend API
Pre-emptively refresh tokens before expiration for better UX
Best Practices Secure Storage
// Good: Store in memory
class TokenManager {
constructor() {
this.token = null;
this.expiresAt = null;
}
setToken(tokenData) {
this.token = tokenData.token;
this.expiresAt = new Date(tokenData.expires);
}
isTokenExpired() {
return !this.token || new Date() >= this.expiresAt;
}
}
Automatic Refresh
async function getValidToken() {
if (tokenManager.isTokenExpired()) {
const response = await fetch('/v1/oauth/token/machine', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: process.env.API_KEY,
secretKey: process.env.SECRET_KEY
})
});
if (response.ok) {
const data = await response.json();
tokenManager.setToken(data.data);
}
}
return tokenManager.token;
}
Security Considerations Credential Security Never expose API keys or secret keys in client-side code
Store credentials in environment variables or secure configuration
Use different credentials for different environments
Network Security Always use HTTPS in production
Implement proper certificate validation
Consider certificate pinning for high-security applications
Integration Examples Node.js Example
const https = require('https');
async function obtainToken(apiKey, secretKey) {
const data = JSON.stringify({ apiKey, secretKey });
const options = {
hostname: 'auth.your-service.tld',
port: 443,
path: '/v1/oauth/token/machine',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
let body = '';
res.on('data', (chunk) => body += chunk);
res.on('end', () => {
if (res.statusCode === 200) {
resolve(JSON.parse(body).data);
} else {
reject(new Error(`HTTP ${res.statusCode}: ${body}`));
}
});
});
req.on('error', reject);
req.write(data);
req.end();
});
}
Python Example
import requests
import os
from datetime import datetime, timezone
def obtain_token():
url = "https://auth.your-service.tld/v1/oauth/token/machine"
payload = {
"apiKey": os.getenv("API_KEY"),
"secretKey": os.getenv("SECRET_KEY")
}
response = requests.post(url, json=payload)
response.raise_for_status()
data = response.json()["data"]
return {
"token": data["token"],
"expires_at": datetime.fromisoformat(data["expires"].replace('Z', '+00:00'))
}
# Usage
try:
token_data = obtain_token()
print(f"Token obtained, expires at: {token_data['expires_at']}")
except requests.RequestException as e:
print(f"Failed to obtain token: {e}")
05 September 2025