04 Auth
4.2 Resource Auth - Revisiting Resource Behaviors
Now that we have some core Scrypto auth concepts, let’s see how it ties together in practice. Back in Chapter 3, we discussed that resources can have an owner denoted by the
OwnerRole. We also discussed that resources can have resource behaviors such as allowing it to be “mintable”. Resource behaviors also had accompanying roles we needed to configure such as the minter and minter_updater role. Our examples were contrived for simplicity, such that we set the resource owner to OwnerRole::None and allowed anyone to perform resource actions by configuring the role's AccessRule to allow_all. We'll revisit those examples to help us understand how auth works with Scrypto while layering on our previous understanding of resource behaviors.//Resource Owners
Let's start by discussing resource owners, or more broadly, "entity owners." Each entity, whether it's a package, component, or resource, has an owner, and these entity owners all function in the same way. The configuration of entity owners can be done using an
OwnerRole construct. For instance, when creating resources, whether they are fungible resources using ResourceBuilder::new_fungible() or non-fungible resources using ResourceBuilder::new_non_fungible(), we are required to configure an OwnerRole.let hello_tokem = ResourceBuilder::new_fungible( OwnerRole::Updatable( rule!(require(owner_badge.resource_address())) ) ) .metadata(metadata!( init { "name" => "Hello Token", locked; "symbol" => "HT", locked; } )) .mint_initial_supply(1000);Line 3: We’ve configured the
In previous examples, we’ve conveniently configured to
OwnerRole to OwnerRole::Updatable, which means the resource owner’s AccessRule can be updated.Line 4: The AccessRule of the OwnerRole which is conditioned to require an owner_badge before the resource owner can be accessed.In previous examples, we’ve conveniently configured to
OwnerRole::None for convenience, but here, we’ve set our OwnerRole to be Updatable and we've mapped the owner to an AccessRule which requires an owner_badge. This badge must be present to be considered an owner. Meaning, if there is a transaction which requires access to privileged actions reserved to a resource owner, the owner_badge must be present as part of the transaction to access the owner role and permit the the action.OwnerRole Configurations
There are three in total we can consider when setting the
OwnerRole:OwnerRole::Fixed(AccessRule)- Sets the ownerAccessRulemapping as fixed which can never be changed after it has been set.OwnerRole::Updatable(AccessRule)- Sets the ownerAccessRulemapping as a updatable which can always be changed so long as the badge(s) set by theAccessRuleis present.OwnerRole::None- Sets the owner as none, indicating that this entity does not have an owner; surrendering certain privileges reserved to the owner.
Resource Owner Privilege
One privilege reserved for the resource owner is the ability to configure metadata after a resource has been created. Let’s take a look at the snippet below:
let hello_token = ResourceBuilder::new_fungible( OwnerRole::Updatable( rule!(require(owner_badge.resource_address())) ) ) .metadata(metadata!( init { "name" => "Hello Token", locked; "symbol" => "HT", locked; } )) .mint_initial_supply(1000);You can see that we’ve set the metadata already and each metadata entry has been locked. The resource owner can’t update these metadata entries after the resource has been created, but the resource owner can always add additional metadata entries and configure whether they can be
updatable or locked. This can be done by creating a method to edit the metadata or through the transaction manifest explained in Chapter 5: Introduction to Transactions on Radix with the Transaction Manifest.Using Resource Owner as a Fallback Auth
Sometimes, there is no need to overcomplicate your auth configuration, in which case, you can simply default it to
OWNER. The OWNER is a shorthand with an AccessRule which maps back to the OwnerRole configurations.let hello_tokens = ResourceBuilder::new_fungible( OwnerRole::Updatable( rule!(require(owner_badge.resource_address())) ) ) .metadata(metadata!( init { "name" => "Hello Token", locked; "symbol" => "HT", locked; } )) .mint_roles(mint_roles!( minter => OWNER; minter_updater => OWNER; )) .mint_initial_supply(1000);Line 14-15:
OWNER is a shorthand that maps back to the AccessRule defined within the OwnerRole configuration.Configuring an owner role can be a straightforward path to setting up resource behaviors while using the owner as a fallback for your auth. This way, you don’t have to worry about any mental overhead of figuring out the structure of your auth while having a safeguard around your resource behavior actions. You can always re-configure resource auth to at a later point by accessing the resource owner.Deferring the OwnerRole
Depending on your particular case, you may not need any auth at all. In such case, you can set the
OwnerRole to OwnerRole::None as we’ve done in previous examples. Just be aware that this means you’ve chosen to surrender the ability to configure the metadata module after the resource has been created. As a result, all metadata (or lack thereof) in the resource definition will forever be final and no longer mutable by anyone, even if you’ve set metadata entries to be updatable.let hello_tokens = ResourceBuilder::new_fungible(OwnerRole::None) .metadata(metadata!( init { "name" => "Hello Token", updatable; } )) .mint_initial_supply(1000);Metadata entries are not re-configurable if you’ve set the resource owner to
OwnerRole::None even if you’ve set the entry to updatable.//Resource Roles
We’ve talked about the
OwnerRole extensively. Let’s now talk about the pre-defined resource behavior roles. Let’s take a look so we can see what we’re talking about.let my_bucket = ResourceBuilder::new_fungible(OwnerRole::None) .metadata(metadata!( init { "name" => "Hello Token", locked; "symbol" => "HT", locked; } )) .mint_roles(mint_roles!( minter => rule!(allow_all); minter_updater => rule!(deny_all); )) .mint_initial_supply(1000);Every resource behavior comes with corresponding pre-defined roles. Each of these pre-defined roles comes in pairs, the role that performs the action (e.g minter) and the role which updates the
AccessRule of the preceding role (e.g minter_updater). These are “pre-defined” roles, because they’re already defined by the engine. For a resource to be “mintable”, a minter that is responsible for minting supply of a resource and a minter_updater which has permissions to update the AccessRule of the minter exists. These pre-defined roles are mapped to an AccessRule which determines how the roles are accessed and its permissions. Each pre-defined role’s AccessRule must then be configured before the resource behavior is enabled.You can find all the corresponding pre-defined roles for each resource behavior in Chapter 3.3 Resource Behaviors.
Pre-defined roles are straightforward and don’t have any other configuration like the
OwnerRole does. Their role’s permission is limited to their corresponding behavior and inferred by their role name. For example, a minter has the permission to mint additional supply of the resource. However, the minter can’t update its own AccessRule. There’s another specific role for that permission: the minter_updater. The minter_updater can update the AccessRule of the minter and it can also update its own AccessRule. This pattern persist for all pre-defined roles.Setting the role’s AccessRule to allow_all, as we did for the minter will allow anyone to access the minter role and effectively give permission to mint additional supplies of the resource. Whereas setting the role’s AccessRule to deny_all, as we did for the minter_updater restricts anyone from accessing the minter_updater role and denies permission to update the AccessRule of the minter.//Configuring Pre-defined Roles
Of course, we can configure the role’s
AccessRule to require a badge we determine before the role can be accessed instead of having simple allow_all/deny_all configurations. We can have a simple straightforward auth model where we simply set the AccessRule to OWNER to fallback to the resource owner as we shown before (if we’ve set a resource owner), but we can also just have each role require its own specific badges.let my_bucket = ResourceBuilder::new_fungible(OwnerRole::None) .metadata(metadata!( init { "name" => "Hello Token", locked; "symbol" => "HT", locked; } )) .mint_roles(mint_roles!( minter => rule!(require(minter_badge.resource_address())); minter_updater => rule!(require(minter_updater_badge.resource_address())); )) .mint_initial_supply(1000);While even though we’ve mapped each role’s
AccessRule to require different badges, it's of course entirely possible that all the badges can be owned by one person. It'll be up to you as how these badges are to be distributed.//Resource Roles Do Not Overlap
Scrypto auth model can be simple and straightforward, by simply setting any resource auth to fall back to the owner, but we can also be granular with our permission settings as well. But what if we have an
OwnerRole, yet also decide to have a different AccessRule mapping to the pre-defined roles? Does the resource owner supersede the pre-defined roles? Remember that roles are used to define the boundaries between permissions.let my_bucket = ResourceBuilder::new_fungible( OwnerRole::Updatable( rule!(require(owner_badge.resource_address())) ) ) .metadata(metadata!( init { "name" => "Hello Token", locked; "symbol" => "HT", locked; } )) .mint_roles(mint_roles!( minter => rule!(require(minter_badge.resource_address())); minter_updater => rule!(require(minter_updater_badge.resource_address())); )) .mint_initial_supply(1000);In the provided snippet, we've configured the
When configuring the
AccessRule for the OwnerRole, minter, and minter_updater to require different badges. Assuming these badges are distributed to three different individuals, each person who possesses the corresponding badge has now assumed their role, and the authorization boundaries are maintained among badge holders.It might seem natural to assume that as a resource owner, you can supersede other roles. However, because permissions have been delegated to other roles, even if you hold the owner_badge as the resource owner, the OwnerRole does not overlap with the minter.When configuring the
minter role within the resource definition or after the resource creation, it's essential to note that assigning the minter role effectively means transferring the authority to perform resource behaviors away from the owner.