Skip to main content

Client Credentials Grant

The Client Credentials grant is designed for machine-to-machine (M2M) authentication where no user interaction is required. This flow is used when applications need to access their own resources or when acting on behalf of themselves rather than a user.

Overview of Client Credentials Grant

The Client Credentials flow is the simplest OAuth 2.0 grant type, designed for confidential clients that can securely store credentials. Unlike user-centric flows, there is no user authentication or consent step—the application authenticates itself directly with the authorization server.

Use Cases:

  • Backend Services: Server-to-server communication between microservices
  • Batch Jobs: Automated processes that run on a schedule (ETL pipelines, data synchronization)
  • CLI Tools: Command-line applications used by developers or administrators
  • Daemon Applications: Background services that don't interact with users
  • System Integrations: Applications that need to access FHIR resources for administrative purposes

Why Use Client Credentials: Client Credentials is appropriate when the application itself is the resource owner, not acting on behalf of a specific user. The tokens issued are tied to the application's identity and permissions, not to any individual user.

Key Benefits:

  • Simple Authentication Flow: Single request to obtain tokens, no redirects or user interaction required
  • High Security: Requires secure storage of client credentials on the backend server
  • Suitable for Automation: Perfect for scheduled jobs and automated workflows
  • No User Context: Access resources based on application permissions, not user permissions
  • Efficient: Minimal overhead compared to user-interactive flows

Client Credentials Flow

Flow Steps in Detail

Step 1: Token Request

The application directly requests an access token from the token endpoint using its client credentials:

POST /w/{tenant}/oauth/api/v1/token HTTP/1.1
Host: api.haste.health
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=backend-service-id&
client_secret=your-client-secret&
scope=system/*.read system/*.write

Parameters:

ParameterRequiredDescription
grant_typeYesMust be client_credentials
client_idYes*Your application's client identifier (*if not using Basic Auth header)
client_secretYes*Your application's client secret (*if not using Basic Auth header)
scopeOptionalSpace-delimited list of requested scopes (defaults to pre-configured scopes)

Scope Format for System Access:

  • system/*.read - Read access to all resource types
  • system/*.write - Write access to all resource types
  • system/Patient.read - Read access to Patient resources only
  • system/Observation.write - Write access to Observation resources only

Step 2: Token Response

The authorization server validates the client credentials and returns an access token:

Success Response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "system/*.read system/*.write"
}

Response Fields:

FieldDescription
access_tokenJWT token to use for API requests
token_typeAlways Bearer for OAuth 2.0
expires_inToken lifetime in seconds (typically 3600 = 1 hour)
scopeGranted scopes (may differ from requested if some were denied)

Note: Client Credentials flow does not return:

  • refresh_token - Not needed; request new token when current expires

Step 3: Access Protected Resources

Use the access token to call FHIR APIs:

Request:

GET /w/{tenant}/{project}/api/v1/fhir/r4/Patient HTTP/1.1
Host: api.haste.health
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

Step 4: Token Expiration and Renewal

Since Client Credentials tokens don't include refresh tokens, request a new access token before the current one expires:

Error Handling

Token Request Errors

Error CodeDescriptionResolution
invalid_requestMissing or invalid required parameterCheck grant_type, client_id, and client_secret
invalid_clientClient authentication failedVerify client_id and client_secret are correct
invalid_scopeRequested scope is invalid or not authorizedRequest only authorized scopes for your client
unauthorized_clientClient not authorized for client credentials grantContact administrator to enable this grant type
unsupported_grant_typeGrant type not supportedUse grant_type=client_credentials
server_errorAuthorization server errorRetry with exponential backoff

Example Error Response

{
"error": "invalid_client",
"error_description": "Client authentication failed. Invalid client_secret provided.",
"error_uri": "https://api.haste.health/errors/invalid_client"
}

API Request Errors

Status CodeDescriptionResolution
401 UnauthorizedToken is missing, invalid, or expiredRequest a new access token
403 ForbiddenToken is valid but lacks required scopeCheck granted scopes, request additional permissions
429 Too Many RequestsRate limit exceededImplement exponential backoff and retry
500 Server ErrorInternal server errorRetry with backoff, contact support if persistent

Comparison with Other Flows

FeatureClient CredentialsAuthorization Code + PKCERefresh Token
Use CaseMachine-to-machineUser authenticationToken renewal
User InteractionNoneRequiredNone
Client TypeConfidential onlyPublic & confidentialAny
Client SecretRequiredNot required (PKCE)Not required
Refresh TokenNot issuedIssuedUsed to get new tokens
User ContextNoYesYes (from original auth)
ComplexityLowHighLow
SecurityHigh (if secrets protected)HighestHigh
Best ForBackend services, batch jobsSPAs, mobile appsLong sessions

Resources