Authentication in Scout API tests
Scout supports two ways to authenticate API tests:
- API keys via the
requestAuthfixture (best forapi/*endpoints) - Interactive session cookies via the
samlAuthfixture (best forinternal/*endpoints)
Both return headers you can spread into apiClient requests (apiKeyHeader or cookieHeader).
| Endpoint | Recommended auth | Fixture |
|---|---|---|
Public APIs (usually starting with api/*) |
API key | requestAuth |
Internal APIs (usually starting with internal/*) |
Cookie-based session | samlAuth |
Many Kibana APIs use a few standard headers:
kbn-xsrf: required for most non-safe requests (POST,PUT,PATCH,DELETE) when Kibana’s XSRF protection is enabled (default), unless the route opts out / is allowlisted. Kibana also acceptskbn-version, butkbn-xsrfis easier for tests. It’s safe to include onGET.x-elastic-internal-origin: kibana: marks the request as an internal API request (required to callinternal/*endpoints when internal APIs are restricted). It’s safe to include onapi/*too.Content-Type: application/json;charset=UTF-8: include when you send a JSON request body.elastic-api-version: some endpoints are versioned and require this header (the required value depends on the endpoint).
Generate credentials once (often in beforeAll) and reuse them:
Available methods on requestAuth:
| Method | Description |
|---|---|
getApiKeyForViewer() |
Shorthand for getApiKey('viewer') |
getApiKeyForPrivilegedUser() |
Elevated non-admin role; uses editor (most) or developer (Elasticsearch serverless projects) |
getApiKeyForAdmin() |
Shorthand for getApiKey('admin') (full access); avoid unless required |
getApiKey(role) |
Create an API key for a predefined role by name (the role must exist in the deployment) |
getApiKeyForCustomRole(roleDescriptor) |
Create an API key scoped to a custom Kibana/Elasticsearch role descriptor |
let viewerApiKey: RoleApiCredentials;
apiTest.beforeAll(async ({ requestAuth }) => {
viewerApiKey = await requestAuth.getApiKeyForViewer();
});
apiTest('calls a public API', async ({ apiClient }) => {
const res = await apiClient.get('api/console/api_server', {
headers: { ...viewerApiKey.apiKeyHeader, 'kbn-xsrf': 'scout' },
responseType: 'json',
});
expect(res.statusCode).toBe(200);
});
Use getApiKeyForCustomRole() when you need fine-grained Kibana/Elasticsearch privileges:
let credentials: RoleApiCredentials;
apiTest.beforeAll(async ({ requestAuth }) => {
credentials = await requestAuth.getApiKeyForCustomRole({
elasticsearch: {
cluster: [],
indices: [{ names: ['logstash-*'], privileges: ['read', 'view_index_metadata'] }],
},
kibana: [
{
spaces: ['*'],
base: [],
feature: { discover: ['read'] },
},
],
});
});
apiTest('can read discover resources', async ({ apiClient }) => {
const res = await apiClient.get('api/my-feature/data', {
headers: {
...credentials.apiKeyHeader,
'kbn-xsrf': 'scout',
},
responseType: 'json',
});
expect(res.statusCode).toBe(200);
});
Use an interactive session to simulate how the Kibana UI calls internal endpoints:
Available methods on samlAuth:
| Method | Description |
|---|---|
asInteractiveUser(role) |
Get a cookieHeader for a built-in role name (for example viewer) or a custom role descriptor |
apiTest('calls an internal endpoint', async ({ apiClient, samlAuth }) => {
const { cookieHeader } = await samlAuth.asInteractiveUser('viewer');
const res = await apiClient.get('internal/some/endpoint', {
headers: { ...cookieHeader, 'kbn-xsrf': 'scout', 'x-elastic-internal-origin': 'kibana' },
responseType: 'json',
});
expect(res.statusCode).toBe(200);
});
asInteractiveUser() can also take a custom role descriptor:
apiTest('calls an internal endpoint with custom privileges', async ({ apiClient, samlAuth }) => {
const { cookieHeader } = await samlAuth.asInteractiveUser({
kibana: [{ spaces: ['*'], base: [], feature: { discover: ['read'] } }],
elasticsearch: {
indices: [{ names: ['logstash-*'], privileges: ['read', 'view_index_metadata'] }],
},
});
const res = await apiClient.get('internal/some/endpoint', {
headers: { ...cookieHeader, 'kbn-xsrf': 'scout', 'x-elastic-internal-origin': 'kibana' },
responseType: 'json',
});
expect(res.statusCode).toBe(200);
});
- Predefined roles: built-in roles like
admin,editor,viewer. UsegetApiKey()(orgetApiKeyForViewer()etc). Privileges are resolved from the appropriateroles.ymlfile. - Custom roles: roles you define for a specific test with explicit and fine-grained Elasticsearch/Kibana privileges.
- Prefer minimal permissions; avoid
adminunless required. - Reuse credentials within a suite when possible.
- Include required headers (
kbn-xsrf, andx-elastic-internal-originfor internal endpoints). - When testing authorization, cover both allowed and forbidden cases (for example, assert that an under-privileged role receives
403).