The Client Credentials Flow is used for machine-to-machine (M2M) authentication where no user interaction is required. This flow is ideal for backend services, daemons, or automated processes that need to access protected resources on their own behalf rather than on behalf of a user.
- Server-to-server API calls
- Background jobs and scheduled tasks
- Microservices communication
- Automated data synchronization
Client credentials clients must be provisioned manually by Jiko. Contact Jiko support to request a client for machine-to-machine access.
- The client authenticates directly with the authorization server using its credentials.
- The authorization server validates the client and issues an access token.
- The client uses the access token to access protected resources.
Unlike the Authorization Code Flow, there is no user involvement or redirect-based authentication.
The client sends a request to the token endpoint with:
grant_type: Must beclient_credentialsclient_id: The client identifierclient_assertion_type: Specifies the JWT formatclient_assertion: A signed JWT for client authentication (see Private Key JWT)scope: The requested scopes (optional)
POST /api/oauth2/token HTTP/1.1
Host: auth.jiko.io
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&
client_id=your-client-id&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9...&
scope=pockets.read transfers.read{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900
}Note: The client credentials flow does not return a refresh token. When the access token expires, the client must request a new one using the same flow.
- Access tokens issued via client credentials have a lifespan of
15 minutes. - Since there is no refresh token, the client must request a new access token before the current one expires.
- Store your private key securely. Never expose it in client-side code or version control.
- Use short-lived JWTs for the
client_assertion(recommended max 5 minutes). - Rotate your key pair periodically.
- Request only the scopes your application needs.
import os
import time
import jwt
import requests
# Load your private key
private_key = open("private_key.pem", "rb").read()
# Create the client assertion JWT
now = int(time.time())
claims = {
"iss": os.getenv("OAUTH_CLIENT_ID"),
"sub": os.getenv("OAUTH_CLIENT_ID"),
"aud": "https://auth.jiko.io/api/oauth2/token",
# For sandbox "aud": "https://authentication-portal.sandbox-api.jikoservices.com/api/oauth2/token",
"iat": now,
"exp": now + 300, # 5 minutes
"jti": os.urandom(16).hex(),
}
client_assertion = jwt.encode(
claims,
private_key,
algorithm="EdDSA", # set algorithm to match your key
)
# Request the access token
response = requests.post(
"https://auth.jiko.io/api/oauth2/token",
# For sandbox https://authentication-portal.sandbox-api.jikoservices.com/api/oauth2/token
data={
"grant_type": "client_credentials",
"client_id": os.getenv("OAUTH_CLIENT_ID"),
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": client_assertion,
"scope": "pockets.read",
},
)
token_data = response.json()
print(token_data)
access_token = token_data["access_token"]
# Use the access token to call an API
api_response = requests.get(
"https://api.business.jiko.io/api/v2/pockets/",
# For sandbox https://customer-api.sandbox-api.jikoservices.com/api/v2/pockets/
headers={"Authorization": f"Bearer {access_token}"},
)
print(api_response.json())
RFC 6749 - Client Credentials Grant - OAuth 2.0 Client Credentials Grant specification.