On this page

Policy and rule prioritization

Learn how to reorder your policies and rules sequentially from the top down to avoid an undesired priority state.


Learning outcomes

  • Create a policy and rule.
  • Delete a rule.
  • Reorder policy rules correctly.

What you need


Overview

In Okta, policies and their associated rules are evaluated based on an assigned priority. The rule with priority 1 is evaluated first. If its conditions aren't met, Okta moves to priority 2, and so on. When managing these priorities through the Okta Policies API, you need to perform any reordering in a sequential, top-down strategy (P1 to PN).

Key concepts

  • Automatic shifting: When you create a policy or rule and assign a priority that’s already in use, Okta automatically shifts the existing rule down by one. Okta also shifts those below it down by one.
  • The deletion gap: When you delete a rule or policy, Okta doesn’t automatically shift the list. This leaves a gap in the priority sequence (for example, priorities 2, 3, and 4 exist, but 1 is empty). This issue is specific to policies that are v2. See the table in the Differences in policy priority shifts section.
  • The Catch-all Rule: Every policy includes a system-level Catch-all Rule (priority 99) that ensures an outcome if no other rules match. This issue is specific to policies that are v2. See the table in the Differences in policy priority shifts section.

Why top-down order matters

Reordering policy rule priorities in a random sequence often leads to an undesired state. Because Okta shifts existing rules to accommodate new priority assignments, a random update can displace rules that you haven't yet reordered. This results in your rules not being in the sequential order that you expect and users perhaps being denied access or prompted for unnecessary authentication. See Priority drift pitfall example for an example of an undesired state.

Differences in policy priority shifts

Okta addresses the priority order of some policies and rules and how they’re reordered differently. The following table explains how Okta addresses the priority for each policy and its rules.

Note: How Okta handles the policies on the right side of the table is subject to change.

Policies v1 Policies v2
MFA_ENROLL
SIGN_ON
IDP_DISCOVERY
PASSWORD
ACCESS_POLICY
DEVICE_SIGNAL_COLLECTION
PROFILE_ENROLLMENT
POST_AUTH_SESSION
ENTITY_RISK
Priorities start at 1. Priorities start at 0.
Priorities are sequential. Priorities are allowed to have gaps.
Delete requests result in automatic shifts of priority order. Delete requests don’t result in automatic shifts of priority order.
Creates/Updates to priorities of existing values result in shifts of order between old and new. Creates/Updates to priorities of existing values result in shifts between old and new until a shift is no longer needed (since gaps are allowed).

Priority drift pitfall example

In this scenario, you have five rules and want to move Rule Three to the top while keeping others in a specific sequence. If you perform these updates out of order, the automatic shifting mechanism creates a "drift."

Initial state:

Rule Priority
One 1
Two 2
Three 3
Four 4
Five 5

The goal: Move Rule Three to P1, Rule One to P2, and Rule Two to P3.

The random order execution (undesired state):

Step Action Logic result Priority order current state
1 Update Rule Three to P1 Rule 3 becomes P1. Rules One and Two shift down. Rule Three
Rule One
Rule Two
2 Update Rule Two to P3 Rule Two is already at P3 due to the first shift. No change occurs. Rule Three
Rule One
Rule Two
3 Update Rule One to P2 Rule One is already at P2. However, the update triggers a shift for everything below it. Rule Three
Rule One
Gap
Rule Two
Rule Four
Rule Five

Resulting undesired state: Because the updates weren't top-down, Rule Two was pushed to P4, and Rules Four and Five were pushed to P5 and P6, respectively.

Rule Priority
Three 1
One 2
Gap 3
Two 4
Four 5
Five 6

Because rule priorities dictate the evaluation sequence, an undesired state can cause users to match against the wrong security logic. For example, a user who should have been given access by Rule Two (intended P3) may instead be denied or challenged for extra factors. This is because Rule Two drifted to P4, which allowed a more restrictive rule to evaluate first.

To avoid this cascading shift, always treat priority reordering as a top-down synchronization. By updating the rules in order from P1 to PN, you ensure that each subsequent request accounts for the current state of the list. This prevents the drift explained in the example.

Note: The Admin Console always shows P1 to PN priority values and doesn't reflect shifts or gaps.

Reorder rules from the top down

In this section, you learn to reorder rule priorities from the top-down after deleting a rule.

Create the policy and rules

Create an app sign-in policy and four rules for use in this hands-on example scenario.

Note: All API request and response examples are truncated for brevity.

Create a policy

Use the Create a policy (opens new window) operation of the Policies API to create a generic app sign-in policy.

Example request

    curl --request POST \
        --url https://{yourOktaDomain}/api/v1/policies \
    --header 'accept: application/json' \
    --header 'content-type: application/json' \
    --header 'authorization: SSWS 00rtxyX...' \
    --data '{
        "type": "ACCESS_POLICY",
        "name": "New App Sign-In Policy",
        "description": "A new app sign-in policy for testing",
        "status": "ACTIVE",
        "conditions": null
    }'

Example response

    {
        "id": "{policyId}",
        "status": "ACTIVE",
        "name": "New App Sign-In Policy",
        "description": "A new app sign-in policy for testing",
        "system": false,
        "conditions": null,
        ......
        "type": "ACCESS_POLICY"
    }

Create the rules

Create four basic rules for the policy. You need the policy id. Use the Create a policy rule (opens new window) operation of the Policies API.

After you create the first rule, use the same request and change the name to Rule Two and the priority parameter value to 2. Then, repeat for rules three and four.

Note: If you don’t include a priority value, Okta assumes that you want the rule at the bottom of the rules list. This excludes the Catch-all Rule.

Example request

  curl --request POST \
  --url https://{yourOktaDomain}/api/v1/policies/{policyId}/rules \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --header 'authorization: SSWS 00rtxyXw...' \
  --data '{
    "system": false,
    "type": "ACCESS_POLICY",
    "name": "Rule 1",
    "conditions": {
      "riskScore": {
        "level": "ANY"
      },
      "platform": {
        "include": [
          {
            "type": "MOBILE",
            "os": {
              "type": "IOS"
            }
          },
          {
            "type": "MOBILE",
            "os": {
              "type": "ANDROID"
            }
          }
        ]
      }
    },
    "actions": {
      "appSignOn": {
        "access": "ALLOW",
        "verificationMethod": {
          "factorMode": "1FA",
          "reauthenticateIn": "PT2H",
          "type": "ASSURANCE",
          "constraints": [
            {
              "knowledge": {
                "types": [
                  "password"
                ]
              }
            }
          ]
        }
      }
    }
  }'

Example response

{
    "id": "{ruleId}",
    "status": "ACTIVE",
    "name": "Rule 1",
    "priority": 1,
    "created": "2026-01-08T19:47:02.000Z",
    "lastUpdated": "2026-01-08T19:47:02.000Z",
    "system": false,
    "conditions": {
        "people": {
            "users": {
                "exclude": []
            }
        },
        "network": {
            "connection": "ANYWHERE"
        },
        "platform": {
            "include": [
                {
                    "type": "MOBILE",
                    "os": {
                        "type": "IOS"
                    }
                },
                {
                    "type": "MOBILE",
                    "os": {
                        "type": "ANDROID"
                    }
                }
            ],
            "exclude": []
        },
        "riskScore": {
            "level": "ANY"
        },
        "userType": {
            "include": [],
            "exclude": []
        }
    },
    "actions": {
        "appSignOn": {
            "access": "ALLOW",
            "verificationMethod": {
                "factorMode": "1FA",
                "type": "ASSURANCE",
                "reauthenticateIn": "PT2H",
                "constraints": [
                    {
                        "knowledge": {
                            "required": true,
                            "types": [
                                "password"
                            ]
                        }
                    }
                ]
            },
            "keepMeSignedIn": {
                "postAuth": "NOT_ALLOWED"
            }
        }
    },
   "type": "ACCESS_POLICY"
}

There are now four rules for your app sign-in policy. The following is the current state of the rules in your policy:

Rule Priority
One 1
Two 2
Three 3
Four 4
Gaps 5-98
Catch-all Rule 99

Delete a rule

Delete Rule One. You need the rule id to delete it. Use the Delete a policy rule (opens new window) operation of the Policies API.

Example request

    curl --request DELETE
    --url https://{yourOktaDomain}/api/v1/policies/{policyId}/rules/{ruleId} \
    --header 'accept: application/json' \
    --header 'content-type: application/json' \
    --header 'authorization: SSWS 00rtxyX...' \

Now that Rule One is deleted, you may expect that the rule priorities automatically shift up. However, app sign-in policy rules maintain their existing priority. This leaves a gap where Rule One was. The following is the current state of the rule priorities in your policy:

Rule Priority
Gap 1
Two 2
Three 3
Four 4
Gaps 5-98
Catch-all Rule 99

You can verify this by performing a List all policy rules (opens new window) operation to view the current priorities for the policy rules.

Example request

    curl --request GET
    --url https://{yourOktaDomain}/api/v1/policies/{policyId}/rules \
    --header 'accept: application/json' \
    --header 'content-type: application/json' \
    --header 'authorization: SSWS 00rtxyXw...' \

Example response

{
    [
    {
        "id": "rul8yias7nJ3Ik2PK0g7",
        "status": "ACTIVE",
        "name": "Rule 2",
        "priority": 2,
        "created": "2026-01-09T22:16:59.000Z",
        "lastUpdated": "2026-01-09T22:16:59.000Z",
        "system": false,
        ...
    },
    {
        "id": "rul8yibgoaOLrnVYb0g7",
        "status": "ACTIVE",
        "name": "Rule 3",
        "priority": 3,
        "created": "2026-01-09T22:17:17.000Z",
        "lastUpdated": "2026-01-09T22:17:17.000Z",
        "system": false,
       ...
    },
    {
        "id": "rul8yi9ctxGSJuKv10g7",
        "status": "ACTIVE",
        "name": "Rule 4",
        "priority": 4,
        "created": "2026-01-09T22:19:06.000Z",
        "lastUpdated": "2026-01-09T22:19:06.000Z",
        "system": false,
        ...
    },
   {
        "id": "rul8ydeltgh2cpnHt0g7",
        "status": "ACTIVE",
        "name": "Catch-all Rule",
        "priority": 99,
        "created": "2026-01-06T22:45:19.000Z",
        "lastUpdated": "2026-01-06T22:45:19.000Z",
        "system": true,
        "conditions": null,
        . . .
    }
    ]
}

Rule reorder

Begin at the top with Rule Two and perform a Replace a policy rule (opens new window) operation, changing the priority parameter from 2 to 1.

Example request

curl --request PUT
--url https://{yourOktaDomain}/api/v1/policies/{policyId}/rules/{ruleId} \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'authorization: SSWS 00rtxyXw...' \
--data '{
    "id": "{ruleId}",
    "status": "ACTIVE",
    "name": "Rule 2",
    "priority": 1,
    "created": "2026-01-08T19:50:43.000Z",
    "lastUpdated": "2026-01-08T19:50:43.000Z",
    "system": false,
    "conditions": {
        "people": {
            "users": {
                "exclude": []
            }
        },
        "network": {
            "connection": "ANYWHERE"
        },
        "platform": {
            "include": [
                {
                    "type": "MOBILE",
                    "os": {
                        "type": "IOS"
                    }
                },
                {
                    "type": "MOBILE",
                    "os": {
                        "type": "ANDROID"
                    }
                }
            ],
            "exclude": []
        },
        "riskScore": {
            "level": "ANY"
        },
        "userType": {
            "include": [],
            "exclude": []
        }
    },
    "actions": {
        "appSignOn": {
            "access": "ALLOW",
            "verificationMethod": {
                "factorMode": "1FA",
                "type": "ASSURANCE",
                "reauthenticateIn": "PT2H",
                "constraints": [
                    {
                        "knowledge": {
                            "required": true,
                            "types": [
                                "password"
                            ]
                        }
                    }
                ]
            },
            "keepMeSignedIn": {
                "postAuth": "NOT_ALLOWED"
            }
        }
    },
    "type": "ACCESS_POLICY"
}'

The priority of Rule Three remains the same at P3. There's now a gap between Rule Two at P1 and Rule Three at P3. The following is the current state of the rule priorities in your policy:

Rule Priority
Two 1
Gap 2
Three 3
Four 4
Gaps 5-98
Catch-all Rule 99

You can verify this by performing a List all policy rules (opens new window) operation to view the current priorities for the policy rules.

Update the priority for rules three and four by repeating the previous steps. When you finish, the following should be the state of the rule priorities in your policy:

Previous state Current state
Rule Two: P1 Rule Two: P1
Gap P2 Rule Three: P2
Rule Three: P3 Rule Four: P3
Rule Four: P4 Gaps: P4-P98
Gaps: 5-98 Catch-all Rule P99
Catch-all Rule 99

You can verify this by performing a List all policy rules (opens new window) operation to view the current priorities for the policy rules.

Conclusion

Knowing the differences in rule prioritization for the Okta policies is fundamental to maintaining a predictable and secure identity environment. Follow a top-down synchronization strategy to ensure that your logic remains free from cascading shifts that occur during non-sequential API updates.