The Aton Health API uses OAuth 2.0 with the client credentials grant type for server-to-server authentication. This method is ideal for backend applications and services.
Overview
The client credentials flow allows your application to authenticate directly with the Microsoft identity platform using your application's credentials (client ID and client secret).
sequenceDiagram
participant App as Your Application
participant Azure as Microsoft Identity Platform
participant API as Aton Health API
App->>Azure: POST /oauth2/v2.0/token (credentials)
Azure-->>App: Access Token (expires in 1 hour)
App->>API: API Request + Bearer Token
API-->>App: API Response
Getting an Access Token
Endpoint
Required Parameters
Send as application/x-www-form-urlencoded:
| Parameter | Value | Description |
|---|---|---|
grant_type |
client_credentials |
OAuth 2.0 grant type |
client_id |
Provided by Aton Health | Your application's client ID |
client_secret |
Provided by Aton Health | Your application's client secret |
scope |
Provided by Aton Health | API resource and permissions |
Request Example
curl -X POST "https://login.microsoftonline.com/5178eeaf-1f56-44cb-940e-012fe79c2845/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id={your_client_id}" \
-d "client_secret={your_client_secret}" \
-d "scope={api_scope}"
Response Format
{
"token_type": "Bearer",
"expires_in": 3599,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik..."
}
Response Fields
| Field | Description |
|---|---|
token_type |
Always "Bearer" for this grant type |
expires_in |
Token lifetime in seconds (typically 3599 = ~1 hour) |
access_token |
JWT token to use for API requests |
Using the Access Token
Include the access token in the Authorization header of all API requests:
curl -X GET "https://api.aton.health/api/v1/referrals" \
-H "Authorization: Bearer {access_token}"
Code Examples
Python
import os
import requests
from datetime import datetime, timedelta
class AtonHealthAuth:
"""
Schema for Aton Health Patient Referrals API authentication data.
"""
def __init__(self):
self.client_id = os.getenv('ATON_CLIENT_ID')
self.client_secret = os.getenv('ATON_CLIENT_SECRET')
self.scope = os.getenv('ATON_API_SCOPE')
self.access_token = None
self.expires_at = None
def get_access_token(self):
"""
Get a new access token or return a cached valid token.
"""
if self.access_token and self.expires_at > datetime.now():
return self.access_token
url = f"https://login.microsoftonline.com/5178eeaf-1f56-44cb-940e-012fe79c2845/oauth2/v2.0/token"
data = {
'grant_type': 'client_credentials',
'client_id': self.client_id,
'client_secret': self.client_secret,
'scope': self.scope
}
response = requests.post(url, data=data)
response.raise_for_status()
token_data = response.json()
self.access_token = token_data['access_token']
expires_in = token_data['expires_in'] - 60 # 1-minute buffer before actual expiration
self.expires_at = datetime.now() + timedelta(seconds=expires_in)
return self.access_token
def make_authenticated_request(self, method, url, **kwargs):
"""
Make an authenticated request to the Aton Health Patient Referrals API.
"""
token = self.get_access_token()
headers = kwargs.get('headers', {})
headers['Authorization'] = f'Bearer {token}'
kwargs['headers'] = headers
return requests.request(method, url, **kwargs)
# Usage example
auth = AtonHealthAuth()
response = auth.make_authenticated_request('GET', 'https://api.aton.health/health/ping')
pong = response.json()
Node.js
const axios = require('axios');
class AtonHealthAuth {
constructor() {
this.clientId = process.env.ATON_CLIENT_ID;
this.clientSecret = process.env.ATON_CLIENT_SECRET;
this.scope = process.env.ATON_API_SCOPE;
this.accessToken = null;
this.expiresAt = null;
}
async getAccessToken() {
if (this.accessToken && this.expiresAt > Date.now()) {
return this.accessToken;
}
const url = `https://login.microsoftonline.com/5178eeaf-1f56-44cb-940e-012fe79c2845/oauth2/v2.0/token`;
const data = new URLSearchParams({
grant_type: 'client_credentials',
client_id: this.clientId,
client_secret: this.clientSecret,
scope: this.scope
});
try {
const response = await axios.post(url, data, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
this.accessToken = response.data.access_token;
this.expiresAt = Date.now() + (response.data.expires_in - 60) * 1000; // 1-minute buffer before actual expiration
return this.accessToken;
} catch (error) {
throw new Error(`Failed to get access token: ${error.message}`);
}
}
async makeAuthenticatedRequest(method, url, config = {}) {
const token = await this.getAccessToken();
const headers = {
...config.headers,
'Authorization': `Bearer ${token}`
};
return axios({ method, url, ...config, headers });
}
}
// Usage example
const auth = new AtonHealthAuth();
auth.makeAuthenticatedRequest('GET', 'https://api.aton.health/health/ping')
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error.message));
.NET
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
public class AtonHealthAuth
{
private readonly HttpClient _httpClient;
private readonly string _clientId;
private readonly string _clientSecret;
private readonly string _scope;
private string _accessToken;
private DateTime _expiresAt;
public AtonHealthAuth()
{
_httpClient = new HttpClient();
_clientId = Environment.GetEnvironmentVariable("ATON_CLIENT_ID");
_clientSecret = Environment.GetEnvironmentVariable("ATON_CLIENT_SECRET");
_scope = Environment.GetEnvironmentVariable("ATON_API_SCOPE");
}
public async Task<string> GetAccessTokenAsync()
{
if (!string.IsNullOrEmpty(_accessToken) && _expiresAt > DateTime.UtcNow)
{
return _accessToken;
}
var url = $"https://login.microsoftonline.com/5178eeaf-1f56-44cb-940e-012fe79c2845/oauth2/v2.0/token";
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "client_credentials"),
new KeyValuePair<string, string>("client_id", _clientId),
new KeyValuePair<string, string>("client_secret", _clientSecret),
new KeyValuePair<string, string>("scope", _scope)
};
var content = new FormUrlEncodedContent(parameters);
var response = await _httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
var jsonResponse = await response.Content.ReadAsStringAsync();
var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(jsonResponse);
_accessToken = tokenResponse.AccessToken;
_expiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn - 60); // 1 minute buffer before actual expiration
return _accessToken;
}
public async Task<HttpResponseMessage> MakeAuthenticatedRequestAsync(HttpMethod method, string url, HttpContent content = null)
{
var token = await GetAccessTokenAsync();
var request = new HttpRequestMessage(method, url);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
if (content != null)
{
request.Content = content;
}
return await _httpClient.SendAsync(request);
}
private class TokenResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
}
}
Environment Variables Setup
Store your credentials securely using environment variables or a key management solution:
Development (.env file)
ATON_CLIENT_ID=your-client-id
ATON_CLIENT_SECRET=your-client-secret
ATON_API_SCOPE=your-api-scope
Production
Set these variables in your production environment (Azure App Service, AWS Lambda, etc.)
Error Handling
Common Errors
| Error | Status Code | Description | Solution |
|---|---|---|---|
invalid_client |
401 | Invalid client ID or secret | Verify credentials with Aton Health |
invalid_scope |
400 | Invalid or unauthorized scope | Check scope value provided by Aton Health |
invalid_grant |
400 | Invalid grant_type parameter | Ensure grant_type is 'client_credentials' |
Error Response Format
{
"error": "invalid_client",
"error_description": "AADSTS70002: Error validating credentials...",
"error_codes": [70002],
"timestamp": "2024-10-15 12:34:56Z",
"trace_id": "abcd1234-...",
"correlation_id": "efgh5678-..."
}
Testing Your Implementation
1. Validate Token Acquisition
# Test with curl
curl -X POST "https://login.microsoftonline.com/5178eeaf-1f56-44cb-940e-012fe79c2845/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope={scope}"
2. Test API Access
# Use the acquired token
curl -X GET "https://api.aton.health/health/ping" \
-H "Authorization: Bearer {access_token}"
Security Considerations
Security Best Practices - Never log or expose client secrets in code or logs - Use secure storage for credentials (Azure Key Vault, AWS Secrets Manager) - Implement token caching to avoid unnecessary token requests - Handle token refresh gracefully in your application - Monitor for authentication failures and implement alerting
Troubleshooting
Token Expired (401 Unauthorized)
- Cause: Access token has expired (lifetime ~1 hour)
- Solution: Request a new access token and retry the request
Invalid Credentials (401 Unauthorized)
- Cause: Incorrect authentication url, Client ID, Client Secret, or Scope
- Solution: Verify credentials with the Aton Health team
Forbidden (403 Forbidden)
- Cause: Valid token but insufficient permissions for the requested resource
- Solution: Contact Aton Health to review your application's scope and permissions
Need Help?
Contact our integration team at integration-support@atonhealth.com