# Security Level rule based on other Security Levels

**URL:** <https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705>\
**Category:** Ignition\
**Tags:** ignition83, security\
**Created:** [May 26, 2026, 10:40am UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705 "2026-05-26T10:40:54Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![malek](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@malek](https://forum.inductiveautomation.com/u/malek)\
**Post date:** [May 26, 2026, 10:40am UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/1 "2026-05-26T10:40:54Z")

</div>

Hello,  
Is there a way to create a Security Level rule based on another custom Security Level, rather than using Roles or Security Zones?

For example, let’s say I have the following security groups:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/9/b9a33d1b9a8c7c19e1206d0460d6bde8aa8d8cfd.png)

And I would like all users with the Manager role in PlantA to automatically have the Intern role in PlantB.

Is it possible to create such a rule?

Thank you.

---

<div class="post-metadata">

**Author:** ![Jasmine\_Quick](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jasmine_quick/32/80380_2.png) [@Jasmine\_Quick](https://forum.inductiveautomation.com/u/Jasmine_Quick)\
**Post date:** [May 26, 2026, 10:50am UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/2 "2026-05-26T10:50:06Z")

</div>

You could try using the [security rules](https://www.docs.inductiveautomation.com/docs/8.3/platform/security/identity-provider-authentication-strategy/security-level-rules?utm_term=&utm_campaign=002+Ignition+Performance+Max&utm_source=adwords&utm_medium=ppc&hsa_acc=1942977828&hsa_cam=23148918670&hsa_grp=&hsa_ad=&hsa_src=x&hsa_tgt=&hsa_kw=&hsa_mt=&hsa_net=adwords&hsa_ver=3&gad_source=1&gad_campaignid=23144530532&gbraid=0AAAAAD-80zgYXXvb9cfEsIX4Mm5GXu3NZ&gclid=CjwKCAjwidXQBhAZEiwA4egw6PiPRPFh40SvVxsNThsn7yTQSKetcUuRjNoOlF3GSrwXGQ_0MULMdxoCC84QAvD_BwE) to make your own definitions?

---

<div class="post-metadata">

**Author:** ![malek](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@malek](https://forum.inductiveautomation.com/u/malek)\
**Post date:** [May 26, 2026, 11:19am UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/3 "2026-05-26T11:19:32Z")

</div>

Yes, using Security Rules is exactly what I want to do. However, I cannot figure out how to create a rule based on another custom Security Level rather than on a Role ( `{user:roles}`) or Security Zone (`{security-zones}`).

To make my question more clear, let’s use the example from my original post.  
I want to create a rule for PlantB/Intern that grants access to:

- users with the PlantB\_Intern role
- AND users already in the PlantA/Manager security level

So the rule would look something like this:

_containsAny({user:roles}, 'PlantB\_Intern') || \<something I don't know\>_

For this example, let’s assume the PlantA/Manager security level is defined by some complicated expression and not simply by the PlantA\_Manager role.

---

<div class="post-metadata">

**Author:** ![malek](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@malek](https://forum.inductiveautomation.com/u/malek)\
**Post date:** [May 27, 2026, 9:18am UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/4 "2026-05-27T09:18:10Z")

</div>

I just had an idea to use the `isAuthorized` expression function:

```python
isAuthorized(true, 'Authenticated/Custom Roles/PlantA/Manager')

```

However, it did not work. The only result was the following error in the log:

```python
com.inductiveautomation.ignition.gateway.auth.security.level.rules.SecurityLevelRuleFactoryException: Unable to create security level rule of type 'expression'

```

---

<div class="post-metadata">

**Author:** ![danielps1818](https://avatars.discourse-cdn.com/v4/letter/d/ecae2f/32.png) [@danielps1818](https://forum.inductiveautomation.com/u/danielps1818)\
**Post date:** [May 27, 2026, 11:45am UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/5 "2026-05-27T11:45:19Z")

</div>

Maybe I'm not understanding correctly but it doesn't make sense what you are trying to do.

You are setting roles for an user. An user can have a role, but can't have a role configured based on another role it makes no sense because you wouldn't use this role, you would use the first one.

For what I can see, you are treating security level rules as roles.

However, I belive that what you are trying to do it is possible. I'm not entirily sure on your problem. If you could detail it a bit would be helpful.

Check the documentation:

> **[Special Object Reference​ - Security Level Rules | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.1/platform/security/identity-provider-authentication-strategy/security-level-rules#special-object-reference)**
>
> When a user accesses a project, they can fall into one or more of many Security Levels that you can set up. The Security Level Rules determine if the user has that Security Level or not. The rules come in the form of expressions that can access any...

---

<div class="post-metadata">

**Author:** ![malek](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@malek](https://forum.inductiveautomation.com/u/malek)\
**Post date:** [May 27, 2026, 12:39pm UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/6 "2026-05-27T12:39:54Z")

</div>

@danielps1818 thank you for your reply.

Please let’s be precise with the terminology: Roles, Security Levels, and Security Zones.

Let me describe our situation:

Roles are defined in the Identity Provider.  
The Identity Provider in our company is managed by another team, and making changes to roles is complicated for us.

Because of that, we created custom Security Levels under “Groups”. These are much more flexible for our needs, and we use more complicated expressions and manual exceptions to assign users to these groups.

Now I want to create another Security Level branch called “Actions”, with levels such as _canPressStartButton_. Many instances of my Start button across multiple pages will use this Security Level.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/2/d223ce8108a7d4cf38adb72f6dadd48ef8c7e1c7.png)

The idea is to define `canPressStartButton` using an expression based on our Groups (for example: all users in `GroupA` except users in `GroupB`)

This would allow us to centrally manage permissions without having to update every individual button whenever requirements change.

---

<div class="post-metadata">

**Author:** ![danielps1818](https://avatars.discourse-cdn.com/v4/letter/d/ecae2f/32.png) [@danielps1818](https://forum.inductiveautomation.com/u/danielps1818)\
**Post date:** [May 27, 2026, 2:44pm UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/7 "2026-05-27T14:44:40Z")

</div>

Now I understand.

* * *

For your situation you have 2 options:

> [@malek](#):
>
> `isAuthorized(true, 'Authenticated/Custom Roles/PlantA/Manager')`

Doing what you did here ↑. However I belive that the error is occuring because that level hasn't loaded yet. Not sure.

Or simply copying and pasting the full code of the original level. I will not recommend doing this.

* * *

However, I would like to share what is our solution. We think it's a good aproach and maybe it could help you.

In our case, the users roles are also managed by the AD.  
What we have as our security rules are only your "Actions".  
Each rule calls the same script

`runScript("core.has_role", 0, {attribute-source:idTokenClaims:roles}, "ID-Rule")`

This script throws a query to our database. The table looks like this:

| SECURITY\_ID | NAME | ROLES |
| --- | --- | --- |
| PRESS\_BUTTON\_ERROR | Allow to press the error button | ["Administrator","Agent","Security"] |
| PRESS\_BUTTON\_SAVE | Allow to press the save button | ["Administrator","Agent","Operator"] |
| VISUALIZATION\_ALARMS | Allowed to enter the alarms view. | ["Administrator"] |

The script looks something like this:

> **has\_role function**
>
> ```python
> def has_role(role_list, rule):
> rules_ds = system.db.runNamedQuery(
> 'GET_SECURITY_LEVEL_RULE',
> {"SECURITY_LEVEL_ID": rule}
> )
> 	
> if len(rules_ds) != 1:
> return False
> 	
> rule_roles = system.util.jsonDecode(rules_ds.getValueAt(0, 0))
> for role in role_list:
> if role in rule_roles:
> return True
> return False
> 
> ```

It will return true when the role is allowed to do that rule.

This way, you can link rules to independent roles. No need to have multiple roles or having that tree structure. You configure the security level rules (the actions) and you configure in the database what roles are allowed to do.

For your case:

- Action
  - canPressStartButton

When checking if it can press the button it will launch:

```python
has_role(["PlantA/Manager", ...], "canPressStartButton")

```

This will search in the database the specific rule:

| SECURITY\_ID | NAME | ROLES |
| --- | --- | --- |
| canPressStartButton | Allow to press the start button | ["PlantA/Manager", "PlantB/Intern", "Manteinance", ...] |

Because the rule allows PlantA/Manager_s_ to execute that, it will allow to press the button (it will return true).

A lot of this explanation has been done on the fly, so it will not be exactly like that.  
Hope I helped on something and hope you find a solution.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [May 27, 2026, 2:54pm UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/8 "2026-05-27T14:54:54Z")

</div>

I haven't really played with this feature yet, but I suspect you need to be using Security Level Rules:

> **[Security Level Rules | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.3/platform/security/identity-provider-authentication-strategy/security-level-rules)**
>
> When a user accesses a project, they can fall into one or more of many Security Levels that you can set up. The Security Level Rules determine if the user has that Security Level or not. The rules come in the form of expressions that can access any...

Particularly note the use of the expression language to extract information from the IdP's roles and apply that to your custom security levels.

It is really important to use this feature for custom security instead of UI expression bindings, as only true security levels can be attached to tags.

You may find my Integration Toolkit's iterator expressions helpful for complex cases, in lieu of `runScript()` expressions (like Daniel's).

(Your custom levels need to be under "Authenticated" in the hierarchy, or the user attributes won't be available.)

---

<div class="post-metadata">

**Author:** ![malek](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@malek](https://forum.inductiveautomation.com/u/malek)\
**Post date:** [May 28, 2026, 12:28pm UTC](https://forum.inductiveautomation.com/t/security-level-rule-based-on-other-security-levels/115705/9 "2026-05-28T12:28:00Z")

</div>

@danielps1818 and @pturmel Thank you both for your help.  
I will use some `runScript` expression.
