---
title: "Role Assignment Module"
url: "https://radix-wiki.miow.me/contents/tech/core-concepts/role-assignment-module"
updated: 2026-10-03
description: "The Role Assignment module is the native object module that stores an object's permissions. Every globalized object carries one, and its state is deliberately…"
---

# Role Assignment Module

| Layer | Object module |
| --- | --- |
| Type | Native [blueprint](/contents/tech/core-concepts/blueprints-and-packages), attached to globalized objects |
| Stores | One owner-role field, one key-value collection of role to rule |
| Max roles | 50 per module |
| Max role name | 100 bytes |
| Reserved names | Any name beginning `_`; `_owner_` and `_self_` are defined |
| Defined in | [`object_modules/role_assignment`](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/object_modules/role_assignment/package.rs) |

## Introduction

The **Role Assignment module** is the native object module that stores an object's permissions. Every globalized object carries one, and its [state is deliberately small](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/object_modules/role_assignment/substates.rs): a single field holding the owner role, and one key-value collection mapping a role key to an [access rule](/contents/tech/core-concepts/access-rules-and-auth-zones). [Blueprints](/contents/tech/core-concepts/blueprints-and-packages) declare which roles guard which methods; this module holds what each role currently means, and can be updated after deployment without touching the code.

Storing permissions as module state rather than as [component](/contents/tech/core-concepts/components) fields is what makes them readable from outside. The rules of any live component can be queried through the Gateway like any other substate, so the current authority over a mint, a withdrawal, or a metadata change is a matter of public record rather than of reading the blueprint and trusting it.

## The owner role

[The owner role](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine-interface/src/blueprints/resource/role_assignment.rs) is declared once at instantiation, as one of three values:

- `OwnerRole::None` – no owner at all
- `OwnerRole::Fixed(rule)` – an owner rule that can never be changed by anyone
- `OwnerRole::Updatable(rule)` – an owner rule the owner may change

Internally these become an `OwnerRoleEntry` of a rule plus an updater, where the updater is `None`, `Owner`, or `Object`. When the updater is `None`, [the field is written immutable at creation](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/object_modules/role_assignment/package.rs) rather than merely guarded, so the immutability is a property of the substate and not of a rule that could later be relaxed.

The third value, `Object`, lets the object itself rotate its owner, and it is what makes a pre-allocated [smart account](/contents/tech/core-protocols/smart-accounts) upgradable into a badge-controlled one. [A pre-securified object](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/blueprints/util/securify.rs) is created with its owner rule set to the virtual signature badge of the key that addresses it and the updater set to `Object`, plus a `securify` role guarded by the same rule. Calling `securify` does three things in order: it sets the `securify` role to `DenyAll`, mints the owner badge, and sets the owner role to require that badge. The first step is what makes the conversion one-way; after it, nothing can call `securify` again.

The owner role also decides more than it appears to. Because an undefined role resolves to the owner rule, the owner is the effective default authority over every role the blueprint declares and the instantiator did not assign.

## Roles, names, and the reserved namespace

Beyond the owner, roles are ordinary named entries. [The module validates them on the way in](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/object_modules/role_assignment/package.rs) rather than on use, and the validation is worth knowing before designing a role set:

- At most `MAX_ROLES`, 50 roles per module.
- A role name is at most `MAX_ROLE_NAME_LEN`, 100 bytes, and must pass the same name check as other identifiers.
- **Every name beginning with an underscore is reserved.** Attempting to define or set one fails with `UsedReservedRole`. Only two reserved names are defined by the system, `_owner_` and `_self_`, and both may be referenced in a role list even though neither can be assigned.
- The Role Assignment module cannot hold roles for itself. Passing it as a target module fails with `UsedReservedSpace`.
- The rule attached to a role is validated for depth and node count at assignment time, so an over-complex rule is rejected when it is set, not when it is tested.

Roles are also mutable by design. A role's rule can be reassigned later by whoever the object's permissions allow, which is how a project rotates a compromised admin badge or hands an authority to a governance component without redeploying. The audit trail for such a change is the transaction that made it.

## How blueprints use it

A blueprint does not check roles in its method bodies. It declares, per method, one of four [method accessibility](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine-interface/src/blueprints/resource/role_assignment.rs) values: `Public`, `RoleProtected` with a list of role names, `OwnPackageOnly`, or `OuterObjectOnly`, the last used by the Validator blueprint so that only the [Consensus Manager](/contents/tech/core-concepts/consensus-manager) can reach certain methods. The engine resolves the declaration to a rule through this module and tests it before the body runs.

For [resources](/contents/tech/core-concepts/asset-oriented-programming) the same machinery appears under fixed names. The mint, burn, freeze, recall, deposit, withdraw, and non-fungible-data-update authorities are [seven named roles on the resource manager](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine-interface/src/blueprints/resource/mod.rs), each with a paired `_updater` role, which is why a token's permissions can be read on-ledger as a set of rules and reported as locked when the updater is `DenyAll`. That reading is how this wiki dates a token's authorities without relying on the issuing team's description of them.

The common patterns fall out of the same two pieces: a [badge](/contents/tech/core-concepts/badges) requirement for admin authority, a `CountOf` requirement for N-of-M multi-signature, and a `global_caller` requirement to let one named component act on another.

## External Links

- [Radix Docs: Access Rules & Roles](https://docs.radixdlt.com/docs/advanced-accessrules)
- [radixdlt-scrypto: `role_assignment.rs` (OwnerRole, RoleKey, MethodAccessibility)](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine-interface/src/blueprints/resource/role_assignment.rs)
- [radixdlt-scrypto: role assignment native package (validation and reserved names)](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/object_modules/role_assignment/package.rs)
- [radixdlt-scrypto: role assignment substates (the stored shape)](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/object_modules/role_assignment/substates.rs)
- [radixdlt-scrypto: `securify.rs` (presecurified owner roles and the one-way securify step)](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/blueprints/util/securify.rs)
- [radixdlt-scrypto: `authorization.rs` (role resolution and the owner fallback)](https://github.com/radixdlt/radixdlt-scrypto/blob/main/radix-engine/src/system/system_modules/auth/authorization.rs)
