Appearance
Authentication
Streamline APIs use OAuth 2.0 Client Credentials for authentication, combined with subscription keys for access control.
WARNING
All requests must use HTTPS. HTTP requests and unauthenticated requests will fail.
Quick Start
Every API request requires two things:
| Credential | Header | Description |
|---|---|---|
| Access Token | Authorization: Bearer <token> | OAuth 2.0 token for authentication |
| Subscription Key | Ocp-Apim-Subscription-Key: <key> | Identifies your API subscription |
Getting Your Credentials
After completing the onboarding process, you'll receive:
| Credential | Description |
|---|---|
| Client ID | Your application's unique identifier |
| Client Secret | Secret key for token generation |
| Subscription Key(s) | One key per API subscription |
Protect Your Credentials
- Store credentials securely (use environment variables or a secrets manager)
- Never commit credentials to version control
- Never expose credentials in client-side code
- The
client_secretcannot be recovered if lost
Get an Access Token
Request a token from the authorization server:
Token Endpoint: https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token
bash
curl --request POST \
--url https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'client_id=YOUR_CLIENT_ID' \
--data 'client_secret=YOUR_CLIENT_SECRET' \
--data 'grant_type=client_credentials'curl --request POST \
--url https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'client_id=YOUR_CLIENT_ID' \
--data 'client_secret=YOUR_CLIENT_SECRET' \
--data 'grant_type=client_credentials'js
const response = await fetch(
'https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
grant_type: 'client_credentials',
}),
}
)
const { access_token } = await response.json()const response = await fetch(
'https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
grant_type: 'client_credentials',
}),
}
)
const { access_token } = await response.json()python
import requests
response = requests.post(
'https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token',
data={
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET',
'grant_type': 'client_credentials',
}
)
access_token = response.json()['access_token']import requests
response = requests.post(
'https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token',
data={
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET',
'grant_type': 'client_credentials',
}
)
access_token = response.json()['access_token']csharp
var client = new HttpClient();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", "YOUR_CLIENT_ID"),
new KeyValuePair<string, string>("client_secret", "YOUR_CLIENT_SECRET"),
new KeyValuePair<string, string>("grant_type", "client_credentials")
});
var response = await client.PostAsync(
"https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token",
content
);
var json = await response.Content.ReadFromJsonAsync<JsonObject>();
var accessToken = json["access_token"].ToString();var client = new HttpClient();
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", "YOUR_CLIENT_ID"),
new KeyValuePair<string, string>("client_secret", "YOUR_CLIENT_SECRET"),
new KeyValuePair<string, string>("grant_type", "client_credentials")
});
var response = await client.PostAsync(
"https://auth-api-demo.streamline.laboremus.ug/realms/streamline-test-realm/protocol/openid-connect/token",
content
);
var json = await response.Content.ReadFromJsonAsync<JsonObject>();
var accessToken = json["access_token"].ToString();Token Response
json
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 300
}{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 300
}| Field | Description |
|---|---|
access_token | The Bearer token to use in API requests |
token_type | Always Bearer |
expires_in | Token lifetime in seconds |
Token Expiration
Tokens expire after the time specified in expires_in. Request a new token before the current one expires.
Error Response
json
{
"error": "invalid_client",
"error_description": "Invalid client credentials"
}{
"error": "invalid_client",
"error_description": "Invalid client credentials"
}Using the Access Token
Include both the token and subscription key in every request:
bash
curl --request GET \
--url 'https://api.streamline.laboremus.ug/your-endpoint' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIs...' \
--header 'Ocp-Apim-Subscription-Key: your-subscription-key'curl --request GET \
--url 'https://api.streamline.laboremus.ug/your-endpoint' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIs...' \
--header 'Ocp-Apim-Subscription-Key: your-subscription-key'js
const response = await fetch('https://api.streamline.laboremus.ug/your-endpoint', {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Ocp-Apim-Subscription-Key': 'your-subscription-key'
}
})const response = await fetch('https://api.streamline.laboremus.ug/your-endpoint', {
headers: {
'Authorization': `Bearer ${accessToken}`,
'Ocp-Apim-Subscription-Key': 'your-subscription-key'
}
})python
response = requests.get(
'https://api.streamline.laboremus.ug/your-endpoint',
headers={
'Authorization': f'Bearer {access_token}',
'Ocp-Apim-Subscription-Key': 'your-subscription-key'
}
)response = requests.get(
'https://api.streamline.laboremus.ug/your-endpoint',
headers={
'Authorization': f'Bearer {access_token}',
'Ocp-Apim-Subscription-Key': 'your-subscription-key'
}
)csharp
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "your-subscription-key");
var response = await client.GetAsync("https://api.streamline.laboremus.ug/your-endpoint");client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "your-subscription-key");
var response = await client.GetAsync("https://api.streamline.laboremus.ug/your-endpoint");Subscription Keys
Each API requires its own subscription key. You cannot use a single key across multiple APIs.
| Method | Example |
|---|---|
| Header (recommended) | Ocp-Apim-Subscription-Key: your-key |
| Query parameter | ?subscription-key=your-key |
INFO
Subscription keys are provisioned during onboarding. Contact our team to subscribe to additional APIs.