Skip to main content
Version: Next

Access control

Access control allows making certain parts of the program accessible/visible and making other parts inaccessible/invisible.

In Flow and Cadence, there are two types of access control:

  1. Access control on objects in account storage using capability security.

    Within Flow, a caller is not able to access an object unless it owns the object or has a specific reference to that object. This means that nothing is truly public by default. Other accounts can not read or write the objects in an account unless the owner of the account has granted them access by providing references to the objects.

  2. Access control within contracts and objects using access keywords.

    For the explanations of the following keywords, we assume that the defining type is either a contract, where capability security doesn't apply, or that the caller would have valid access to the object governed by capability security.

The high-level reference-based security (point 1 above) will be covered in a later section.

Top-level declarations (variables, constants, functions, structures, resources, interfaces) and fields (in structures, and resources) are always only able to be written to and mutated (modified, such as by indexed assignment or methods like append) in the scope where it is defined (self).

There are five levels of access control defined in the code that specify where a declaration can be accessed or called.

  • Public or access(all) means the declaration is accessible/visible in all scopes.

    This includes the current scope, inner scopes, and the outer scopes.

    For example, a public field in a type can be accessed using the access syntax on an instance of the type in an outer scope. This does not allow the declaration to be publicly writable though.

    An element is made publicly accessible / by any code by using the access(all) keyword.

  • Entitled access means the declaration is only accessible/visible to the owner of the object, or to references that are authorized to the required entitlements.

    A reference is considered authorized to an entitlement if that entitlement appears in the auth portion of the reference type.

    For example, an access(E, F) field on a resource R can only be accessed by an owned (@R-typed) value, or a reference to R that is authorized to the E and F entitlements (auth(E, F) &R).

    An element is made accessible by code in the same containing type by using the access(E) syntax, described in more detail in the entitlements section below.

  • access(account) means the declaration is only accessible/visible in the scope of the entire account where it is defined. This means that other contracts in the account are able to access it,

    An element is made accessible by code in the same account (e.g. other contracts) by using the access(account) keyword.

  • access(contract) means the declaration is only accessible/visible in the scope of the contract that defined it. This means that other types and functions that are defined in the same contract can access it, but not other contracts in the same account.

    An element is made accessible by code in the same contract by using the access(contract) keyword.

  • Private or access(self) means the declaration is only accessible/visible in the current and inner scopes.

    For example, an access(self) field can only be accessed by functions of the type is part of, not by code in an outer scope.

    An element is made accessible by code in the same containing type by using the access(self) keyword.

Access level must be specified for each declaration

To summarize the behavior for variable declarations, constant declarations, and fields:

Declaration kindAccess modifierRead scopeWrite scopeMutate scope
letaccess(self)Current and innerNoneCurrent and inner
letaccess(contract)Current, inner, and containing contractNoneCurrent and inner
letaccess(account)Current, inner, and other contracts in same accountNoneCurrent and inner
letaccess(all)AllNoneCurrent and inner
letaccess(E)All with required entitlementsNoneCurrent and inner
varaccess(self)Current and innerCurrent and innerCurrent and inner
varaccess(contract)Current, inner, and containing contractCurrent and innerCurrent and inner
varaccess(account)Current, inner, and other contracts in same accountCurrent and innerCurrent and inner
varaccess(all)AllCurrent and innerCurrent and inner
varaccess(E)All with required entitlementsCurrent and innerCurrent and inner

To summarize the behavior for functions:

Access modifierAccess scope
access(self)Current and inner
access(contract)Current, inner, and containing contract
access(account)Current, inner, and other contracts in same account
access(all)All
access(E)All with required entitlements

Declarations of structures, resources, events, and contracts can only be public. However, even though the declarations/types are publicly visible, resources can only be created from inside the contract they are declared in.


_10
// Declare a private constant, inaccessible/invisible in outer scope.
_10
//
_10
access(self) let a = 1
_10
_10
// Declare a public constant, accessible/visible in all scopes.
_10
//
_10
access(all) let b = 2


_91
// Declare a public struct, accessible/visible in all scopes.
_91
//
_91
access(all) struct SomeStruct {
_91
_91
// Declare a private constant field which is only readable
_91
// in the current and inner scopes.
_91
//
_91
access(self) let a: Int
_91
_91
// Declare a public constant field which is readable in all scopes.
_91
//
_91
access(all) let b: Int
_91
_91
// Declare a private variable field which is only readable
_91
// and writable in the current and inner scopes.
_91
//
_91
access(self) var c: Int
_91
_91
// Declare a public variable field which is not settable,
_91
// so it is only writable in the current and inner scopes,
_91
// and readable in all scopes.
_91
//
_91
access(all) var d: Int
_91
_91
// Arrays and dictionaries declared without (set) cannot be
_91
// mutated in external scopes
_91
access(all) let arr: [Int]
_91
_91
// The initializer is omitted for brevity.
_91
_91
// Declare a private function which is only callable
_91
// in the current and inner scopes.
_91
//
_91
access(self) fun privateTest() {
_91
// ...
_91
}
_91
_91
// Declare a public function which is callable in all scopes.
_91
//
_91
access(all) fun publicTest() {
_91
// ...
_91
}
_91
_91
// The initializer is omitted for brevity.
_91
_91
}
_91
_91
let some = SomeStruct()
_91
_91
// Invalid: cannot read private constant field in outer scope.
_91
//
_91
some.a
_91
_91
// Invalid: cannot set private constant field in outer scope.
_91
//
_91
some.a = 1
_91
_91
// Valid: can read public constant field in outer scope.
_91
//
_91
some.b
_91
_91
// Invalid: cannot set public constant field in outer scope.
_91
//
_91
some.b = 2
_91
_91
// Invalid: cannot read private variable field in outer scope.
_91
//
_91
some.c
_91
_91
// Invalid: cannot set private variable field in outer scope.
_91
//
_91
some.c = 3
_91
_91
// Valid: can read public variable field in outer scope.
_91
//
_91
some.d
_91
_91
// Invalid: cannot set public variable field in outer scope.
_91
//
_91
some.d = 4
_91
_91
// Invalid: cannot mutate a public field in outer scope.
_91
//
_91
some.f.append(0)
_91
_91
// Invalid: cannot mutate a public field in outer scope.
_91
//
_91
some.f[3] = 1
_91
_91
// Valid: can call non-mutating methods on a public field in outer scope
_91
some.f.contains(0)

Entitlements

Entitlements provide granular access control to each member of a composite. Entitlements can be declared using the following syntax:


_10
entitlement E
_10
entitlement F

creates two entitlements called E and F.

Entitlements can be imported from other contracts and used the same way as other types. If using entitlements defined in another contract, the same qualified name syntax is used as for other types:


_10
contract C {
_10
entitlement E
_10
}

Outside of C, E is used with C.E syntax. Entitlements exist in the same namespace as types, so if your contract defines a resource called R, it will not be possible to define an entitlement that is also called R.

Entitlements can be used in access modifiers on struct and resource members to specify which references to those composites are allowed to access those members. An access modifier can include more than one entitlement, joined with either an |, to indicate disjunction or "or", or a ,, to indicate conjunction or "and". So, for example:


_14
access(all) resource SomeResource {
_14
_14
// requires an `E` entitlement to read this field
_14
access(E) let a: Int
_14
_14
// requires either an `E` or an `F` entitlement to read this field
_14
access(E | F) let b: Int
_14
_14
// requires both an `E` and an `F` entitlement to read this field
_14
access(E, F) let b: Int
_14
_14
// intializers omitted for brevity
_14
// ...
_14
}

Given some values with the annotated types (details on how to create entitled references can be found here):


_33
_33
let r: @SomeResource = // ...
_33
let refE: auth(E) &SomeResource = // ...
_33
let refF: auth(F) &SomeResource = // ...
_33
let refEF: auth(E, F) &SomeResource = // ...
_33
_33
// valid, because `r` is owned and thus is "fully entitled"
_33
r.a
_33
// valid, because `r` is owned and thus is "fully entitled"
_33
r.b
_33
// valid, because `r` is owned and thus is "fully entitled"
_33
r.c
_33
_33
// valid, because `refE` has an `E` entitlement as required
_33
refE.a
_33
// valid, because `refE` has one of the two required entitlements
_33
refE.b
_33
// invalid, because `refE` only has one of the two required entitlements
_33
refE.c
_33
_33
// invalid, because `refF` has an `E` entitlement, not an `F`
_33
refF.a
_33
// valid, because `refF` has one of the two required entitlements
_33
refF.b
_33
// invalid, because `refF` only has one of the two required entitlements
_33
refF.c
_33
_33
// valid, because `refEF` has an `E` entitlement
_33
refEF.a
_33
// valid, because `refEF` has both of the two required entitlements
_33
refEF.b
_33
// valid, because `refEF` has both of the two required entitlements
_33
refEF.c

Note particularly in this example how the owned value r can access all entitled members on SomeResource; owned values are not affected by entitled declarations.

Entitlement Mappings

When objects have fields that are child objects, it can often be valuable to have different views of that reference depending on the entitlements one has on the reference to the parent object. Consider the following example:


_23
entitlement OuterEntitlement
_23
entitlement SubEntitlement
_23
_23
resource SubResource {
_23
access(all) fun foo() { ... }
_23
access(SubEntitlement) fun bar() { ... }
_23
}
_23
_23
resource OuterResource {
_23
access(self) let childResource: @SubResource
_23
_23
access(all) fun getPubRef(): &SubResource {
_23
return &self.childResource as &SubResource
_23
}
_23
_23
access(OuterEntitlement) fun getEntitledRef(): auth(SubEntitlement) &SubResource {
_23
return &self.childResource as auth(SubEntitlement) &SubResource
_23
}
_23
_23
init(r: @SubResource) {
_23
self.childResource <- r
_23
}
_23
}

With this pattern, we can store a SubResource on an OuterResource value, and create different ways to access that nested resource depending on the entitlement one posseses. Someone with only an unauthorized reference to OuterResource can only call the getPubRef function, and thus can only get an unauthorized reference to SubResource that lets them call foo. However, someone with a OuterEntitlement-authorized reference to the OuterResource can call the getEntitledRef function, giving them a SubEntitlement-authorized reference to SubResource that allows them to call bar.

This pattern is functional, but it is unfortunate that we are forced to "duplicate" the accessors to SubResource, duplicating the code and storing two functions on the object, essentially creating two different views to the same object that are stored as different functions. To avoid necessitating this duplication, we add support to the language for "entitlement mappings", a way to declare statically how entitlements are propagated from parents to child objects in a nesting hierarchy.

So, the above example could be equivalently written as:


_35
entitlement OuterEntitlement
_35
entitlement SubEntitlement
_35
_35
// specify a mapping for entitlements called `Map`, which defines a function
_35
// from an input set of entitlements (called the domain) to an output set (called the range or the image)
_35
entitlement mapping Map {
_35
OuterEntitlement -> SubEntitlement
_35
}
_35
_35
resource SubResource {
_35
access(all) fun foo() { ... }
_35
access(SubEntitlement) fun bar() { ... }
_35
}
_35
_35
resource OuterResource {
_35
// by referering to `Map` here, we declare that the entitlements we receive when accessing the `childResource` field
_35
// on this resource will depend on the entitlements we possess to the resource during the access.
_35
access(Map) let childResource: @SubResource
_35
_35
init(r: @SubResource) {
_35
self.childResource = r
_35
}
_35
}
_35
_35
// given some value `r` of type `@OuterResource`
_35
let pubRef = &r as &OuterResource
_35
let pubSubRef = pubRef.childResource // has type `&SubResource`
_35
_35
let entitledRef = &r as auth(OuterEntitlement) &OuterResource
_35
let entitledSubRef = entitledRef.childResource // `OuterEntitlement` is defined to map to `SubEntitlement`, so this access yields a value of type `auth(SubEntitlement) &SubResource`
_35
Entitlement
_35
_35
// `r` is an owned value, and is thus considered "fully-entitled" to `OuterResource`,
_35
// so this access yields a value authorized to the entire image of `Map`, in this case `SubEntitlement`
_35
let alsoEntitledSubRef = r.childResource

Entitlement mappings may be used either in accessor functions (as in the example above), or in fields whose types are either references, or containers (structs/resources, dictionaries and arrays). Note that having a reference field will necessarily make the type of the composite non-storage.

Entitlement mappings need not be 1:1; it is valid to define a mapping where multiple inputs map to the same output, or where one input maps to multiple outputs.

Entitlement mappings preserve the "kind" of the set they are mapping; i.e. mapping an "and" set produces an "and" set, and mapping an "or" set produces an "or" set. Because "and" and "or" separators cannot be combined in the same set, attempting to map "or"-separated sets through certain complex mappings may result in a type error. For example:


_10
entitlement mapping M {
_10
A -> B
_10
A -> C
_10
D -> E
_10
}

attempting to map (A | D) through M will fail, since A should map to (B, C) and D should map to E, but these two outputs cannot be combined into a disjunctive set.

Built-in Mutability Entitlements

A prominent use-case of entitlements is to control access to object based on mutability. For example, in a struct/resource/contract, the author would want to control the access to certain fields to be read-only, and while some fields to be mutable, etc.

In order to support this, Cadence hase built-in set of entitlements that can be used to access control base on mutability.

  • Insert
  • Remove
  • Mutate

These are primarily used by built-in array and dictionary functions, but are also usable by any user to control access in their own composite type definitions.

While Cadence does not support entitlement composition or inheritance, the Mutate entitlement is intended to be used as an equivalent form to the conjunction of {Insert, Remove} entitlements.