- Organisation
- Paramètres
- Connecter un outil de posture de sécurité
Connect a security posture tool with the security auditor API key
The Security Auditor role gives an API key read-only access to how your organisation is set up: who can sign in, how they authenticate, which keys and links exist, and, when the plan includes action audits, what happened in the audit log. Give this key to your SSPM or security posture tool, so it can check your organisation against your policies without being able to change anything.
The key reads the organisation's security configuration through the organisationSecurity GraphQL query and the audit log through the auditActions query.
What the key can and cannot access
| The key can | The key cannot |
|---|---|
Call the organisationSecurity and auditActions queries and read every field described on this page. |
Call any other query or mutation, including reading its own organisation's scans, vulnerabilities, tickets or assets. |
| Read metadata about API keys, shared links and integrations: names, prefixes, roles, dates and status. | Read a secret. API keys, shared link tokens and integration credentials are never returned. |
| Read the audit events of the organisation, when the plan includes action audits. | Change a setting, a member, a key or an integration. |
Before you start
- The Admin role in the organisation. Only admins can create API keys.
- A signed-in session. An API key cannot create another key.
- An API key only. The role cannot be given to a member or sent in an invitation.
- Action audits on your plan, if your tool needs
auditActions. See Audit events.
Create the key
Create the key from the GraphQL API, signed in as an admin. Open the sandbox at https://api.ostorlab.co/apis/graphql, see Sandbox, and run:
mutation {
createApiKey(name: "Security posture tool", role: "security_auditor") {
apiKey {
secretKey
}
}
}
Copy secretKey and store it in the secret manager of your tool right away. Ostorlab stores only a hash of the key, so it cannot show it again. An optional expiryDate argument limits the life of the key. See Create and manage API keys for expiry and revocation.
Call the query
Send the key in the X-Api-Key header to https://api.ostorlab.co/apis/graphql_token/:
curl -s https://api.ostorlab.co/apis/graphql_token/ \
-H "X-Api-Key: $OSTORLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ organisationSecurity { settings { isOtpRequired } } }"}'
The query returns the security posture of the organisation the key belongs to. Each section below shows one selection and the shape of its response. You can combine sections in a single query. The values shown are examples.
If your organisation uses an IP allowlist, the tool must call from a listed address.
Settings
The authentication and access settings in effect for the organisation.
{
organisationSecurity {
settings {
isOtpRequired
mfaPromptFrequency
hasObjectLevelAccess
isRestrictedDefaultLevelAccess
hasActionAudits
passwordPolicy {
minLength
requiresUpperAndLowerCase
requiresNumber
requiresSpecialCharacter
}
loginLockout {
failureLimit
cooloffMinutes
}
sessionPolicy {
idleTimeoutMinutes
maxTokenAgeMinutes
}
sso {
enabled
identityProviderEntityId
signOnServiceUrl
signOutServiceUrl
domains
autoProvision
acceptPassword
modifiedTime
}
}
}
}
{
"data": {
"organisationSecurity": {
"settings": {
"isOtpRequired": true,
"mfaPromptFrequency": "EVERY_LOGIN",
"hasObjectLevelAccess": false,
"isRestrictedDefaultLevelAccess": false,
"hasActionAudits": true,
"passwordPolicy": {
"minLength": 12,
"requiresUpperAndLowerCase": true,
"requiresNumber": true,
"requiresSpecialCharacter": true
},
"loginLockout": { "failureLimit": 5, "cooloffMinutes": 30 },
"sessionPolicy": { "idleTimeoutMinutes": 60, "maxTokenAgeMinutes": 1440 },
"sso": {
"enabled": true,
"identityProviderEntityId": "https://idp.example.com/entity",
"signOnServiceUrl": "https://idp.example.com/sso",
"signOutServiceUrl": null,
"domains": ["example.com"],
"autoProvision": true,
"acceptPassword": false,
"modifiedTime": "2026-10-01T09:30:00+00:00"
}
}
}
}
}
mfaPromptFrequencyisEVERY_LOGIN: every password login asks a user with OTP enabled for a token. Logins through Google, GitHub or SAML single sign-on do not ask for one.minLengthisnullwhen no minimum length is enforced.cooloffMinutesisnullwhen a lockout never expires.ssoisnullwhen the organisation has no SAML configuration.acceptPasswordtells whether users of the SSO domains can still sign in with a password.hasActionAuditstells whether audit events are recorded and readable.
Members
The users with access to the organisation, one entry per access.
{
organisationSecurity {
members(page: 1, numberElements: 50) {
members {
id
email
username
role
mfaEnabled
mfaMethods
lastActivityTime
dateJoined
accessCreatedTime
groups {
id
name
}
}
pageInfo {
count
numPages
hasNext
hasPrevious
}
}
}
}
{
"data": {
"organisationSecurity": {
"members": {
"members": [
{
"id": "12",
"email": "alice@example.com",
"username": "alice",
"role": "admin",
"mfaEnabled": true,
"mfaMethods": ["totp", "recovery_codes"],
"lastActivityTime": "2026-10-29T16:02:11+00:00",
"dateJoined": "2026-01-12T08:00:00+00:00",
"accessCreatedTime": "2026-01-12T08:05:00+00:00",
"groups": [{ "id": "3", "name": "Mobile team" }]
}
],
"pageInfo": { "count": 1, "numPages": 1, "hasNext": false, "hasPrevious": false }
}
}
}
}
- Leave out
pageto get every member in one response.pageInfois thennull. mfaEnabledtells whether login requires a one-time token from the user.mfaMethodslists the methods the user enrolled, and can be filled whilemfaEnabledisfalse.lastActivityTimeis the last login of the user. It is refreshed on every token request, so it also tracks API activity.
Groups
The groups of the organisation, with their members and active API keys.
{
organisationSecurity {
groups {
id
name
type
parentId
members
apiKeys {
name
prefix
}
}
}
}
{
"data": {
"organisationSecurity": {
"groups": [
{
"id": "3",
"name": "Mobile team",
"type": "internal",
"parentId": null,
"members": ["alice@example.com", "bob@example.com"],
"apiKeys": [{ "name": "GitHub Actions", "prefix": "AbCdEfGh" }]
}
]
}
}
}
type is the ownership type of the group's owner, one of:
internal: assets the organisation owns.acquisition: assets that came with an acquired company.third_party_service: assets run by an outside provider.rejected: assets marked as not belonging to the organisation.
members lists the emails of the users in the group. apiKeys lists active keys only: not revoked and not expired.
Roles
The roles a member can be given and the permission actions each one grants.
{
organisationSecurity {
roles {
name
permissions
}
}
}
{
"data": {
"organisationSecurity": {
"roles": [
{ "name": "reader", "permissions": ["read", "attack_surface_read", "self_read_write"] },
{ "name": "attack_surface_auditor", "permissions": ["attack_surface_audit", "attack_surface_read", "self_read_write"] }
]
}
}
}
The security_auditor role is not listed: it cannot be assigned to a member.
API keys
The API keys of the organisation, newest first. Revoked keys are left out unless you ask for them.
{
organisationSecurity {
apiKeys(includeRevoked: true) {
prefix
name
role
createdTime
expiryDate
lastUsed
revoked
owners {
id
name
}
}
}
}
{
"data": {
"organisationSecurity": {
"apiKeys": [
{
"prefix": "AbCdEfGh",
"name": "GitHub Actions",
"role": "user",
"createdTime": "2026-09-01T10:00:00+00:00",
"expiryDate": null,
"lastUsed": "2026-10-29T22:15:00+00:00",
"revoked": false,
"owners": [{ "id": "3", "name": "Mobile team" }]
}
]
}
}
}
- The key itself and its hash are never returned.
prefixidentifies the key. expiryDateisnullwhen the key never expires.lastUsedisnullwhen the key was never used, and is recorded at most once per refresh interval, so it can lag behind the last request.ownerslists the groups the key is restricted to. For an admin key it lists every group of the organisation.- Keys that Ostorlab creates for its own scans are not listed.
Invitations
The invitations to join the organisation, newest first.
{
organisationSecurity {
invitations(pending: true) {
id
invitee
role
inviterEmail
createdTime
accepted
status
}
}
}
{
"data": {
"organisationSecurity": {
"invitations": [
{
"id": "41",
"invitee": "carol@example.com",
"role": "user",
"inviterEmail": "alice@example.com",
"createdTime": "2026-10-28T14:20:00+00:00",
"accepted": null,
"status": null
}
]
}
}
}
pending: true returns pending invitations only, pending: false returns answered ones only, and leaving it out returns all. accepted is null while the invitation is pending. status is free text and can be null.
Shared links
The shared access links of the organisation, without their tokens.
{
organisationSecurity {
sharedAccessLinks {
id
prefix
scanId
createdTime
revoked
revokedTime
lastAccessTime
accessCount
}
}
}
{
"data": {
"organisationSecurity": {
"sharedAccessLinks": [
{
"id": "7",
"prefix": "QrStUvWx",
"scanId": "4521",
"createdTime": "2026-10-20T09:00:00+00:00",
"revoked": false,
"revokedTime": null,
"lastAccessTime": "2026-10-27T13:45:00+00:00",
"accessCount": 6
}
]
}
}
}
scanId is null when the link shares the attack surface instead of a scan.
Integrations
A summary of every third-party integration the organisation configured. No credential is returned.
{
organisationSecurity {
integrations {
integrationType
id
name
provider
enabled
createdTime
updatedTime
endpointHost
lastSyncStatus
}
}
}
{
"data": {
"organisationSecurity": {
"integrations": [
{
"integrationType": "JIRA",
"id": "2",
"name": "Security board",
"provider": null,
"enabled": true,
"createdTime": "2026-08-05T11:00:00+00:00",
"updatedTime": "2026-09-14T08:30:00+00:00",
"endpointHost": "example.atlassian.net",
"lastSyncStatus": null
}
]
}
}
}
integrationTypeis one ofJIRA,LINEAR,APP_CENTER,APPCIRCLE,SLACK,VANTA,SOURCE_CODE_OAUTH,GIT_PERSONAL_ACCESS_TOKEN,STANDARD_GIT,SERVICENOW,WEBHOOK,GITHUB_APP_INSTALLATION,ORG_GITHUB_APPLICATION,ORG_GITHUB_APPLICATION_INSTALLATION,AWS_CLOUD_CONNECTOR,GCP_CLOUD_CONNECTOR,AZURE_CLOUD_CONNECTOR,AI_PROVIDER_API_KEYandREMOTE_MCP_SERVER.idis unique per integration type.endpointHostis only the host of the configured endpoint. It isnullwhen the integration has no endpoint, or when its URL is itself a secret.provideris filled for source code integrations.
Audit events
The audit events of the organisation are read with the top-level auditActions query, not through organisationSecurity. Use its cursor mode: pass afterId or first. Events come back oldest first, so you can poll for new ones.
query AuditActions($afterId: Int, $first: Int, $actions: [AuditActionType!]) {
auditActions(afterId: $afterId, first: $first, actions: $actions) {
audits {
id
createdTime
event
action
ipAddress
}
hasMore
nextAfterId
}
}
With the variables { "afterId": 1840, "first": 100, "actions": ["LOGIN_FAILED", "ACCESS_CHANGE"] } the response looks like this.
{
"data": {
"auditActions": {
"audits": [
{
"id": "1841",
"createdTime": "2026-10-29T16:05:00+00:00",
"event": "alice created an API key.",
"action": "ACCESS_CHANGE",
"ipAddress": "203.0.113.7"
}
],
"hasMore": false,
"nextAfterId": 1841
}
}
}
Keep the nextAfterId of each response and send it as afterId in the next call: you then receive only the events you have not read. While hasMore is true, call again right away to page through a backlog. An event is returned only once it is 30 seconds old.
Audit events need the action audit feature on your plan. Without it, auditActions returns an empty list, hasMore is false and nextAfterId is the afterId you sent. The hasActionAudits setting tells you which case you are in.
For every argument, field, event kind and filter, and for the polling steps, see Read the audit log with the API.
Revoke or replace the key
Revoke the key when you stop using the tool or when it leaks. See Revoke or replace a key. A key you revoke stops working at once.
Next steps
- Create and manage API keys
- Read the audit log with the API
- Restrict access with an IP allowlist
- Call the GraphQL API