Preview an organization policy
POST /v1/organizations/{org_id}/policies/{policy_kind}:preview · permission organizations:write
Evaluates a candidate settings object without saving it. The body is the same as for creating or replacing a policy, and the server checks it with the same rules and the same plan gate, so a candidate that PUT would reject is rejected here with the same problem code. Nothing is written: no policy, no audit entry and no event. The request takes no If-Match and no Idempotency-Key, and the response carries no ETag.
The response counts the users the candidate applies to (basis users_in_scope), not the users who would be blocked, with one exception: phishing_resistant (see below). Conditions that are only known at sign-in, or that the policy service does not hold, are not filtered out; not_evaluated lists them so that the count is never read as more than it is.
| Kind | Users counted | not_evaluated |
|---|---|---|
authentication_methods |
Active members of the organization | credentials |
mfa (required_for admins or all) |
Active members of the organization | mfa_enrollment; also admin_scope for admins |
phishing_resistant (required_for admins or all) |
Active members of the organization without an accepted WebAuthn credential (basis users_without_webauthn, see below) |
credential_policy; also admin_scope for admins |
sso_enforcement org_context |
Active members of the organization, minus bypass_user_ids |
federated_sign_in |
sso_enforcement verified_domains |
Active members, plus active users of the environment with an email address on a verified domain of this organization, minus bypass_user_ids |
federated_sign_in |
session |
Active members of the organization | none |
ip_allowlist |
Active members of the organization | client_ip; also admin_scope for admins |
For phishing_resistant, the count and the sample are the users in scope who cannot sign in phishing-resistantly today: users without an active WebAuthn credential (a passkey, or a security key used with a first factor) that the AAGUID allowlist accepts. The allowlist is the candidate's, or the environment's when the candidate's is empty; with an allowlist, a credential counts only if its model is listed and its attestation was verified. Pending, revoked and clone-suspected credentials do not count. credential_policy means that the environment's attestation requirement, the device-bound passkey rule and the authenticator model status are not applied, so the count can be lower than the number of users who would be blocked. When the scope has more than 10,000 users, the response falls back to users_in_scope with passkey_enrollment. If the credential data cannot be read, the request fails with 503 and no count is returned.
required_for none and mode off count nobody. An active member is a member whose membership is active and whose user is not blocked; each user is counted once. admin_scope means that admins is counted as all members, which is how sign-in applies it today. The users of another organization or another environment are never counted.
Request
| Field | Type | Required | Description |
|---|---|---|---|
org_id |
path | yes | Organization ID (org_…). |
policy_kind |
path | yes | Policy kind: authentication_methods, mfa, phishing_resistant, sso_enforcement, session or ip_allowlist. Any other value returns 404. |
settings |
object | yes | The candidate settings object of the kind, with the same fields as for PUT. |
Request body:
{
"settings": {
"required_for": "all",
"allowed_factors": [
"totp",
"webauthn"
],
"enrollment_grace_days": 7
}
}
Response
200 OK. sample holds at most 20 users of the counted set, ordered by ID, with the user ID only.
| Field | Type | Description |
|---|---|---|
organization_id |
string | Organization ID (org_…). |
policy_kind |
string | The previewed kind. |
basis |
string | What affected_count counts: users_in_scope or, for phishing_resistant, users_without_webauthn. New values may be added. |
affected_count |
integer | Number of users that basis counts. |
sample |
array | At most 20 objects with user_id (usr_…). |
not_evaluated |
array | Conditions the count does not filter: admin_scope, credentials, mfa_enrollment, passkey_enrollment, federated_sign_in, client_ip, credential_policy. New values may be added. |
{
"organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
"policy_kind": "mfa",
"basis": "users_in_scope",
"affected_count": 2,
"sample": [
{
"user_id": "usr_01j9xk3m7q8r2s4t6v8w0y2z4b"
},
{
"user_id": "usr_01j9xk3m7q8r2s4t6v8w0y2z4c"
}
],
"not_evaluated": [
"mfa_enrollment"
]
}
Errors
| HTTP | code | When |
|---|---|---|
| 400 | unknown_field |
The body has a field that is not in the schema. |
| 403 | plan_feature_unavailable |
The kind or the AAGUID allowlist requires a higher plan; the problem carries feature and required_plan. |
| 404 | not_found |
The organization does not exist or the kind is unknown. |
| 409 | domain_not_verified |
sso_enforcement with mode verified_domains needs a verified domain on the organization. |
| 409 | connection_test_required |
Turning sso_enforcement on (from off or from no policy) needs a successful test sign-in of the current configuration of at least one of the connection_ids in the last 24 hours. Run a connection test (POST /v1/connections/{connection_id}:test) and try again. |
| 409 | organization_pending_deletion |
The organization is waiting for self-service deletion. |
| 422 | validation_failed |
A settings field is unknown or invalid; errors[] points at /settings/…. |
| 422 | policy_weaker_than_parent |
The setting is weaker than the environment's setting; errors[] points at the weaker field. |
| 422 | at_least_one_method |
authentication_methods leaves no sign-in method. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks the required permission. |
| 429 | rate_limited |
The rate limit was exceeded; retry after the Retry-After period. |
| 503 | service_unavailable |
A dependency is temporarily unavailable (for phishing_resistant, also when the credential data cannot be read); retry after the Retry-After period. |
Example
curl -X POST https://api.eu.keenauth.com/v1/organizations/org_01j9xk3m7q8r2s4t6v8w0y2z4a/policies/mfa:preview \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"settings":{"required_for":"all","allowed_factors":["totp","webauthn"]}}'
keenauth organizations policies preview org_01j9xk3m7q8r2s4t6v8w0y2z4a mfa \
--data '{"settings":{"required_for":"all","allowed_factors":["totp","webauthn"]}}'