Authentication with OAuth 2.0
Every AgencyMax API operation needs an OAuth 2.0 bearer access token (a JWT) in the Authorization header, along with your subscription key.
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Identity provider
The APIs trust tokens issued by the AgencyMax identity provider (the authority). Most agencies use the shared AgencyMax authority. An agency can also be set up with its own authority. Either way, the authority publishes its token endpoint and signing keys in its OpenID Connect discovery document:
{authority}/.well-known/openid-configuration
Your AgencyMax representative will give you the authority URL, a client ID and a client secret for each environment.
Getting a token (client credentials)
For server-to-server integrations, use the OAuth 2.0 client credentials grant. Request the scopes you need, separated by spaces. The list must always include your tenant scope.
curl -X POST "$TOKEN_ENDPOINT" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
--data-urlencode "scope=tenant:acme read:agents write:agents"
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "tenant:acme read:agents write:agents"
}
Example in C#
using var http = new HttpClient();
var tokenResponse = await http.PostAsync(tokenEndpoint, new FormUrlEncodedContent(new Dictionary<string, string> {
["grant_type"] = "client_credentials",
["client_id"] = clientId,
["client_secret"] = clientSecret,
["scope"] = "tenant:acme read:agents"
}));
tokenResponse.EnsureSuccessStatusCode();
var token = await tokenResponse.Content.ReadFromJsonAsync<JsonElement>();
var accessToken = token.GetProperty("access_token").GetString();
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.agencymax.example.com/agency-management/acme/agents/A1001");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
request.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
var response = await http.SendAsync(request);
Scopes
Two kinds of scope control access.
Tenant scope
Tenant-scoped operations need the scope tenant:<tenantIdentifier>, and it must match the tenant identifier in the request URL. A token for tenant acme can call /acme/... but gets 403 Forbidden on /globex/.... See Tenants.
API scopes
Each operation also needs an API-specific scope:
| API | Scope | Grants |
|---|---|---|
| Agency Management | read:agents | Read agents and all related data: certifications, payees, teams, reference data and so on. |
write:agents | Create and update agents and related data. | |
delete:agents | Permanently delete agents. | |
| Agent Onboarding | agent-onboarding:app-configuration:read | Read onboarding app configuration, contracts, covenants and background questions. |
agent-onboarding:applications:read | Read agent applications. | |
agent-onboarding:applications:write | Create, update and validate agent applications. | |
| Business Insights | business-insights:queries:execute | Run business queries. |
business-insights:report-recipes:read | Read report recipes. | |
business-insights:report-recipes:write | Create, update and delete report recipes. | |
| Identity Management | read:users | Read users. |
write:users | Create and update users. | |
read:roles | Read roles. | |
| Webhooks | read:webhook-subscriptions | Read webhook subscriptions and delivery history. |
write:webhook-subscriptions | Create, update and delete webhook subscriptions. |
Upcoming scope renames
The Identity Management and Webhooks scopes are due to move to the newer <api>:<resource>:<action> naming, for example identity:users:read, identity:roles:read and webhooks:subscriptions:write. Any rename will be announced in the Release Notes with a transition period.
Request only the scopes your integration needs.
Token lifetime and caching
- Tokens expire;
expires_ingives the lifetime in seconds. Cache each token and reuse it until shortly before it expires, for example 60 seconds early. Don't request a new token for every API call. The identity provider throttles token requests. - If an API call returns
401 Unauthorizedwith aWWW-Authenticate: Bearer ...header, the token has probably expired. Get a new token and retry once.
Authentication and authorization errors
| Status | Meaning | What to do |
|---|---|---|
401 Unauthorized | The token is missing, malformed or expired, has an invalid signature, or came from an untrusted authority. | Check the Authorization header and get a fresh token. |
403 Forbidden | The token is valid but lacks the tenant scope for the URL's tenant, or lacks the operation's API scope. | Request a token with the right scopes. Contact AgencyMax if your client isn't allowed to request them. |
A 401 or 403 can also come from the API gateway if the subscription key is the problem. See Subscription keys.