# Access authorization
> The Authorization is intrinsically linked with the [Authentication](./identity.md).
## Directives
The Authorization is implemented as a set of [RTD Directives](tree.md#directives).
Directives are executed in a predetermined order until one of them grants access to a resource.
If none of the directives grants access, then the Authorization interrupts request processing and
responds with an authorization error.
> The Authorization directive provider is named `authorization`,
> so the full names of the directives are `authorization:{directive}`.
### `anonymous`
Grants access if its value is `true` and no credentials were provided[^1].
[^1]: Credentials in the request make the
response [non-cacheable](https://datatracker.ietf.org/doc/html/rfc7234#section-3).
### `anyone`
Grants access if its value is `true` and valid credentials were provided.
### `id`
Grants access if resolved Identity matches the value of the URL path segment placeholder named after
the directive's value.
#### Example
Given the Route declaration and corresponding HTTP request:
```yaml
/users/:user-id:
id: "user-id"
```
```http
GET /users/87480f2bd88048518c529d7957475ecd/
Authorization: ...
```
For this request access will be granted if the resolved Identity value
is `87480f2bd88048518c529d7957475ecd`.
### `role`
Grants access if resolved Identity has a role matching the directive's value or one of its values.
```yaml
/code:
role: [developer, reviewer]
```
Access will be granted if the resolved Identity has a role that matches `developer` or `reviewer`.
Read [Roles](#roles) section for more details.
#### Dynamic roles
The `role` directive can be used with a placeholder in the route.
```yaml
/:org-id:
role: app:{org-id}:moderator
```
### `claims`
Grants access if `Bearer` authentication scheme is used
and the Token's claims matches the specified values.
```yaml
/:
auth:claims:
iss: https://id.example.com
sub: someone
aud: stars
```
> If OIDC token claim contains `aud`
> as [an array](https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation), the
> directive will match if at least one value.
At least one property is required.
Values may refer to the Route parameters or the request authority:
```yaml
/secrets/:org-id:
auth:claims:
iss: https://id.org.com
sub: /:org-id
aud: :authority
```
An expression `:domain` will match if the domain in the value of `iss` matches the request
authority, excluding the most specific subdomain.
Issuer `https://accounts.example.com` matches request authorities `images.example.com`
and `sub.images.example.com`, but not `images.another.com`.
```yaml
/images/:user-id:
auth:claims:
iss: :domain
sub: /:org-id
```
### `rule`
The Rule is a collection of authorization directives. It allows access only if all the specified
directives grant access. The value of the `rule` directive can be a single Rule or a list of Rules.
#### Example
```yaml
/commits/:user-id:
rule:
id: user-id
role: developer
```
Access will be granted if an Identity matches a `user-id` placeholder and has a Role of `developer`.
### `input`
Restricts access based on the request body (which must be an object).
```yaml
/commits/:id:
PUT:
auth:role: [developer, reviewer]
auth:input:
- prop: approved
role: reviewer
- prop: message
role: developer
```
The example above restricts access to the `approved` property of the request body to the identity
with the `reviewer` role, and the `message` property to the identity with the `developer` role.
> `auth:input` directive does not grant access by itself.
### `delegate`
Embeds the value of the current Identity into the request body as a property named after the value
of the directive value, and grants access.
The request body must be an object.
> :warning:
> The intended use case for this directive is audit.
> **Using it to pass Identity to the application logic is strongly discouraged.**
## Roles
Role values are strings that can be assigned to an Identity and used for matching with values of
the [`role` directive](#role).
### Hierarchies
Role values are alphanumeric tokens separated by a colon (`:`).
Each token defines a Role Scope, forming a hierarchy.
A Role matches the value of the `rule` directive if that Role has the specified Scope in a
directive.
#### Example
```yaml
/commits/:user-id:
role: developer:senior
```
The example above defines a `role` directive with the specified `developer:senior` Role Scope.
This directive matches the roles `developer:senior` and `developer`,
but it **does not** match the Role `developer:senior:javascript`.
In other words, the Identity must have a specified or more general Role.
> The root-level Role Scope `system` is preserved and cannot be used with the `role` directives.
See also [role management resources](components.md#roles).
## Policies
Component Resource branches cannot have authorization directives.
Instead, they must declare Authorization Policies using `policy` directive to
be attached in the Context to a Resource Tree as a set of Authorization Directives
using `attachment` directive.
This restriction provides a separation of concerns, allowing components to be reused in different
Contexts with varying
access rules.
```yaml
# manifest.toa.yaml
name: posts
exposition:
/:user-id:
GET:
endpoint: observe
policy: read:list
POST:
endpoint: transit
policy: post:submit
/:post-id:
GET:
endpoint: observe
policy: read:post
PUT:
endpoint: assign
policy: post:edit
```
```yaml
# context.toa.yaml
exposition:
/posts:
attachment:
read:
anonymous: true
post:
id: user-id
post:edit:
role: app:posts:editor
```
Policy values as well as [Role](#roles) values define hierarchical Policy Scopes.
In the example above:
- an Attachment `read` attaches Directive `anonymous: true` to both `read:list` and `read:post`
Policy Scopes.
This means that a list of posts and each post can be accessed without authorization.
- an Attachment `post` attaches Directive `id: user-id` to both `post:submit` and `post:edit` Policy
Scopes.
This means that an Identity can submit and edit their own posts.
- an Attachment `post:edit` attaches Directive `role: app:posts:editor` to `post:edit` Policy Scope.
This means that an identity with the role scope `app:posts:editor` can edit posts by any author,
in addition to the fact that the author themselves can do this thanks to the previous Attachment.
### Nesting
Policies are namespace-scoped, meaning they can be attached to any Route under the
corresponding `/{namespace}` prefix.
Attachment is applied to the node where it is declared, as well as its nested nodes.
Directives of the Attachment are applied to the node where the attached Policies are declared, as
well as their nested nodes.
Here's an example of how this works:
```yaml
# manifest.toa.yaml
name: posts
exposition:
/:user-id:
GET:
endpoint: observe
policy: read
/:user-id/:post-id:
GET:
endpoint: observe
policy: read
```
```yaml
# context.toa.yaml
exposition:
/posts:
/:user-id:
attachment:
read:
anonymous: true
/:user-id/:post-id:
attachment:
read:
role: reader
```
In the example above, the same Policy `read` is attached to two Routes with different Directives.
The following example demonstrates the attachment of the `read` Policy to both Routes with the same
Directive:
```yaml
# context.toa.yaml
exposition:
/posts:
attachment:
read:
anonymous: true
```