Authentication
Authenticating against the M&NTIS APIs
The M&NTIS REST APIs (including the Scenario API) are protected by OpenID Connect (Keycloak). Every request must carry a valid access token as a Authorization: Bearer <token> header, plus a couple of context headers that identify which workspace/organization the call applies to.
Endpoints
For a deployment on domain <your-domain> (e.g. mantis-platform.io):
| Purpose | URL |
|---|---|
| API base (Scenario) | https://app.<your-domain>/api/scenario/lab |
| OpenID Connect issuer | https://id.<your-domain>/realms/mantis |
| OIDC discovery document | https://id.<your-domain>/realms/mantis/.well-known/openid-configuration |
| Token endpoint | https://id.<your-domain>/realms/mantis/protocol/openid-connect/token |
The discovery document lists the exact token/authorization endpoints and the scopes supported by your deployment. Ask your M&NTIS administrator for a client (and, for machine-to-machine integrations, a client secret or service account).
1. Obtain an access token
# Resource-owner password grant (or use refresh_token / client_credentials
# depending on how your OIDC client is configured).
curl -X POST "https://id.mantis-platform.io/realms/mantis/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=<your-client-id>" \
-d "username=<your-username>" \
-d "password=<your-password>"
# -> {"access_token": "...", "refresh_token": "...", "expires_in": 300, ...}import requests
OIDC = "https://id.mantis-platform.io/realms/mantis/protocol/openid-connect/token"
def get_access_token(client_id: str, username: str, password: str) -> str:
resp = requests.post(
OIDC,
data={
"grant_type": "password",
"client_id": client_id,
"username": username,
"password": password,
},
)
resp.raise_for_status()
return resp.json()["access_token"]Access tokens are short-lived (a few minutes). Keep the refresh_token and exchange it for a fresh access token when needed (grant_type=refresh_token), exactly as the official mantis CLI does (mantis_api_client/mantis_api_client/oidc.py).
2. Call the API with the token
Pass the token as a Bearer header. Most Scenario endpoints also expect a workspace header (and optionally an organization header) so the platform can resolve your lab quota and permissions:
| Header | Value |
|---|---|
Authorization | Bearer <access_token> |
X-Workspace-Id | your workspace id |
X-Organization-Id | your organization id (optional) |
curl "https://app.mantis-platform.io/api/scenario/lab/version" \
-H "Authorization: Bearer $TOKEN"
curl "https://app.mantis-platform.io/api/scenario/lab/scenario/" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID"import requests
BASE = "https://app.mantis-platform.io/api/scenario/lab"
def api_headers(token: str, workspace_id: str) -> dict:
return {
"Authorization": f"Bearer {token}",
"X-Workspace-Id": workspace_id,
}
resp = requests.get(f"{BASE}/scenario/", headers=api_headers(TOKEN, WORKSPACE_ID))
resp.raise_for_status()
print(resp.json())Some scenario-launching endpoints additionally require the token to carry specific scopes (e.g. scenario:run). These are shown per-operation in the API reference and enforced server-side.
3. Public-access links (advanced)
When creating a lab with public_access_enabled: true, the client performs an OIDC token exchange to mint a token dedicated to the public link, and passes it in the request body as public_access_config. See exchange_token_public_access() in mantis_authz and create_lab_scenario() in the reference client for the exact flow.
Next step
Head to the Quickstart to launch a lab end-to-end with these credentials.

