# ACCESS

The ACCESS statement can be used to manage access grants.

_(since v2.2.0)_

> [!CAUTION]
> Currently, the `ACCESS` statement is an experimental feature intended to be used for validating its suitability and security. As such, it may be subject to breaking changes and may present unidentified security issues. Do not rely on this feature in production applications.

The `ACCESS` statement can be used to manage access grants. It provides the ability to generate access grants using certain access methods, such as bearer keys defined with the [`DEFINE ACCESS ... TYPE BEARER`](/docs/reference/query-language/statements/define/access/bearer.md) statement, as well as the ability to show, revoke and purge such grants.

By default, the `ACCESS` statement will default to referencing access methods defined at the current level specified with the [`USE`](/docs/reference/query-language/statements/use.md) statement. As with other statements, access methods defined at any level can be referenced by using the `ON` clause.

Operations that either create, revoke or purge access grants using the `ACCESS` statement will be logged in the server as long as it is running with the `INFO` level (the default) or any higher verbosity level. These logs are identified by the `surrealdb_core::sql::statements::access` prefix.

### Statement syntax

**SurrealQL Syntax**

```syntax title="SurrealQL Syntax"
ACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ]
	GRANT [ FOR USER @name | FOR RECORD @record ]
	| SHOW [ GRANT @id | ALL | WHERE @expression ] 
	| REVOKE [ GRANT @id | ALL | WHERE @expression ] 
	| PURGE [ EXPIRED | REVOKED [ , EXPIRED | REVOKED ] ] [ FOR @duration ]
```

## `GRANT`

The `GRANT` clause creates and returns a grant for a certain subject using the specified access method. This subject can be a [system user](/docs/learn/security/authentication/authentication.md#system-users) or [record user](/docs/learn/security/authentication/authentication.md#record-users). Access grants can be used to access SurrealDB as that subject until they become expired or revoked.

When creating a grant, a secret (e.g. a key) corresponding with the grant will be returned. This secret should be stored securely, as it will no longer be displayed by SurrealDB, instead being printed as `[REDACTED]` whenever the grant details are shown.

```syntax title="SurrealQL Syntax"
ACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ] 
	GRANT [ FOR USER @name | FOR RECORD @record ]
```

#### Example: grant for automation using system user

```surql
-- Define system user for automation
DEFINE USER automation ON DATABASE PASSWORD 'secret' ROLES VIEWER;
-- Define bearer access method to generate API keys
DEFINE ACCESS api
  ON DATABASE TYPE BEARER FOR USER DURATION FOR GRANT 10d;
-- Generate bearer grant to be used by the automation
ACCESS api GRANT FOR USER automation;
```

```surql title="Response"
-- Query 1
NONE
-- Query 2
NONE
-- Query 3
{
        ac: 'api',
        creation: d'2024-12-16T16:15:51.517384293Z',
        expiration: d'2024-12-26T16:15:51.517386053Z',
        grant: {
                id: 'BNb2pS0GmaJz',
                key:
                  'surreal-bearer-BNb2pS0GmaJz-5eTfQ5uEu8jbRb3oblqVMAt8'
        },
        id: 'BNb2pS0GmaJz',
        revocation: NONE,
        subject: {
                user: 'automation'
        },
        type: 'bearer'
}
```

#### Example: grant for end-user using record user

```surql
-- Create record representing a user
CREATE user:1 CONTENT { name: "tobie" };
-- Define bearer access method to generate API keys
DEFINE ACCESS api
  ON DATABASE TYPE BEARER FOR RECORD DURATION FOR GRANT 10d;
-- Generate bearer grant to be used by the user
ACCESS api GRANT FOR RECORD user:1;
```

```surql title="Response"
-- Query 1
[
        {
                id: user:1,
                name: 'tobie'
        }
]
-- Query 2
NONE
-- Query 3
{
        ac: 'api',
        creation: d'2024-12-16T16:16:41.996932810Z',
        expiration: d'2024-12-26T16:16:41.996934501Z',
        grant: {
                id: 'sRLEKGxObJuM',
                key:
                  'surreal-bearer-sRLEKGxObJuM-iUUFe1vijFDaFDW7jceZJDkX'
        },
        id: 'sRLEKGxObJuM',
        revocation: NONE,
        subject: {
                record: user:1
        },
        type: 'bearer'
}
```

## `SHOW`

The `SHOW` clause displays the details of grants created with a specific access method. The statement allows showing the details of individual grants, all grants or only grants matching a particular SurrealQL expression. Beware that, in situations where grants are automatically created, showing all grants at once may be impractical and filtering is advised.

Note that any secrets (e.g. keys) associated with the grant will not be displayed and instead will be shown as `[REDACTED]`.

```syntax title="SurrealQL Syntax"
ACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ]
	SHOW [ GRANT @id | ALL | WHERE @expression ] 
```

#### Example: Showing the details of a specific grant

```surql
-- Create record representing a user
CREATE user:1 CONTENT { name: "tobie" };
-- Define bearer access method to generate API keys
DEFINE ACCESS api
  ON DATABASE TYPE BEARER FOR RECORD DURATION FOR GRANT 10d;
-- Generate bearer grant to be used by the user
ACCESS api GRANT FOR RECORD user:1;
```

```surql title="Response"
-- Query 1
[
        {
                id: user:1,
                name: 'tobie'
        }
]
-- Query 2
NONE
-- Query 3
{
        ac: 'api',
        creation: d'2024-12-16T16:17:24.903832476Z',
        expiration: d'2024-12-26T16:17:24.903834523Z',
        grant: {
                id: 'JdvDFKMCVYoM',
                key:
                  'surreal-bearer-JdvDFKMCVYoM-0ahEAVY6egVdg33Vs5gc6J4h'
        },
        id: 'JdvDFKMCVYoM',
        revocation: NONE,
        subject: {
                record: user:1
        },
        type: 'bearer'
}
```

```surql
ACCESS api SHOW GRANT JdvDFKMCVYoM;
```

```surql title="Response"
{
        ac: 'api',
        creation: d'2024-12-16T16:17:24.903832476Z',
        expiration: d'2024-12-26T16:17:24.903834523Z',
        grant: {
                id: 'JdvDFKMCVYoM',
                key: '[REDACTED]'
        },
        id: 'JdvDFKMCVYoM',
        revocation: NONE,
        subject: {
                record: user:1
        },
        type: 'bearer'
}
```

#### Example: Showing the details of all grants for users of a certain name

Since the `subject` attribute of grants associated with a record is a record identifier, it can be used as a [record link](/docs/reference/query-language/language-primitives/record-links.md) in order to access any record fields. This can be used to filter grants associated with record users matching certain conditions based on arbitrary data.

```surql
-- Create records representing users
CREATE user:1 CONTENT { name: "tobie" };
CREATE user:2 CONTENT { name: "jaime" };
-- Define bearer access method to generate API keys
DEFINE ACCESS api
  ON DATABASE TYPE BEARER FOR RECORD DURATION FOR GRANT 10d;
-- Generate bearer grants to be used by the users
ACCESS api GRANT FOR RECORD user:1;
ACCESS api GRANT FOR RECORD user:2;
```

```surql title="Response"
-- Query 1
[
        {
                id: user:1,
                name: 'tobie'
        }
]
-- Query 2
[
        {
                id: user:2,
                name: 'jaime'
        }
]
-- Query 3
NONE
-- Query 4
{
        ac: 'api',
        creation: d'2024-12-16T16:18:57.061692071Z',
        expiration: d'2024-12-26T16:18:57.061694228Z',
        grant: {
                id: 'HaJ19zCnP6RI',
                key:
                  'surreal-bearer-HaJ19zCnP6RI-R545vHcTbSCYdHnxIsVnjSFu'
        },
        id: 'HaJ19zCnP6RI',
        revocation: NONE,
        subject: {
                record: user:1
        },
        type: 'bearer'
}
-- Query 5
{
        ac: 'api',
        creation: d'2024-12-16T16:18:57.063673293Z',
        expiration: d'2024-12-26T16:18:57.063674755Z',
        grant: {
                id: 'ND2ZegEHfUGl',
                key:
                  'surreal-bearer-ND2ZegEHfUGl-JGPSr162qJ2bN8kURV8mYaLv'
        },
        id: 'ND2ZegEHfUGl',
        revocation: NONE,
        subject: {
                record: user:2
        },
        type: 'bearer'
}
```

```surql
ACCESS api SHOW WHERE subject.record.name = "tobie";
```

```surql title="Response"
[
        {
                ac: 'api',
                creation: d'2024-12-16T16:18:57.061692071Z',
                expiration: d'2024-12-26T16:18:57.061694228Z',
                grant: {
                        id: 'HaJ19zCnP6RI',
                        key: '[REDACTED]'
                },
                id: 'HaJ19zCnP6RI',
                revocation: NONE,
                subject: {
                        record: user:1
                },
                type: 'bearer'
        }
]
```

## `REVOKE`

The `REVOKE` clause revokes grants created with a specific access method. Revoking a grant ensures that the grant can no longer be used to authenticate. The grant will continue existing in revoked form and the time of the revocation is recorded in the details of the grant. Grants that have already been revoked cannot be revoked again. The statement allows revoking individual grants, all grants or only grants matching a particular SurrealQL expression.

```syntax title="SurrealQL Syntax"
ACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ]
	REVOKE [ GRANT @id | ALL | WHERE @expression ] 
]
```

#### Example: Revoking a specific grant

```surql
-- Create record representing a user
CREATE user:1 CONTENT { name: "tobie" };
-- Define bearer access method to generate API keys
DEFINE ACCESS api
  ON DATABASE TYPE BEARER FOR RECORD DURATION FOR GRANT 10d;
-- Generate bearer grant to be used by the user
ACCESS api GRANT FOR RECORD user:1;
```

```surql title="Response"
-- Query 1
[
        {
                id: user:1,
                name: 'tobie'
        }
]
-- Query 2
NONE
-- Query 3
{
        ac: 'api',
        creation: d'2024-12-17T10:36:09.215762475Z',
        expiration: d'2024-12-27T10:36:09.216227523Z',
        grant: {
                id: 'NJ2I2d7OXxN9',
                key:
                  'surreal-bearer-NJ2I2d7OXxN9-Oa5LqF36IzfURpo6Bhxy9WMF'
        },
        id: 'NJ2I2d7OXxN9',
        revocation: NONE,
        subject: {
                record: user:1
        },
        type: 'bearer'
}
```

```surql
ACCESS api REVOKE GRANT NJ2I2d7OXxN9;
```

```surql title="Response"
[
        [
                {
                        ac: 'api',
                        creation: d'2024-12-17T10:36:09.215762475Z',
                        expiration: d'2024-12-27T10:36:09.216227523Z',
                        grant: {
                                id: 'NJ2I2d7OXxN9',
                                key: '[REDACTED]'
                        },
                        id: 'NJ2I2d7OXxN9',
                        revocation: d'2024-12-17T10:36:52.740438379Z',
                        subject: {
                                record: user:1
                        },
                        type: 'bearer'
                }
        ]
]
```

#### Example: Revoking all grants for users of a certain name

Since the `subject` attribute of grants associated with a record is a record identifier, it can be used as a [record link](/docs/reference/query-language/language-primitives/record-links.md) in order to access any record fields. This can be used to filter grants associated with record users matching certain conditions based on arbitrary data.

```surql
-- Create records representing users
CREATE user:1 CONTENT { name: "tobie" };
CREATE user:2 CONTENT { name: "jaime" };
-- Define bearer access method to generate API keys
DEFINE ACCESS api
  ON DATABASE TYPE BEARER FOR RECORD DURATION FOR GRANT 10d;
-- Generate bearer grants to be used by the users
ACCESS api GRANT FOR RECORD user:1;
ACCESS api GRANT FOR RECORD user:2;
```

```surql title="Response"
-- Query 1
[
        {
                id: user:1,
                name: 'tobie'
        }
]
-- Query 2
[
        {
                id: user:2,
                name: 'jaime'
        }
]
-- Query 3
NONE
-- Query 4
{
        ac: 'api',
        creation: d'2024-12-17T10:42:35.040901759Z',
        expiration: d'2024-12-27T10:42:35.040903414Z',
        grant: {
                id: 'mjSACes6sej4',
                key:
                  'surreal-bearer-mjSACes6sej4-WbEPMgmLTO3Jfg3po4we9m0V'
        },
        id: 'mjSACes6sej4',
        revocation: NONE,
        subject: {
                record: user:1
        },
        type: 'bearer'
}
-- Query 5
{
        ac: 'api',
        creation: d'2024-12-17T10:42:35.043162877Z',
        expiration: d'2024-12-27T10:42:35.043164533Z',
        grant: {
                id: 'RFilJMRp9lZi',
                key:
                  'surreal-bearer-RFilJMRp9lZi-OmflYxXwikDAvm8CNpsWYxd6'
        },
        id: 'RFilJMRp9lZi',
        revocation: NONE,
        subject: {
                record: user:2
        },
        type: 'bearer'
}
```

```surql
ACCESS api REVOKE WHERE subject.record.name = "tobie";
```

```surql title="Response"
[
        [
                {
                        ac: 'api',
                        creation: d'2024-12-17T10:42:35.040901759Z',
                        expiration: d'2024-12-27T10:42:35.040903414Z',
                        grant: {
                                id: 'mjSACes6sej4',
                                key: '[REDACTED]'
                        },
                        id: 'mjSACes6sej4',
                        revocation: d'2024-12-17T10:43:23.944198560Z',
                        subject: {
                                record: user:1
                        },
                        type: 'bearer'
                }
        ]
]
```

## `PURGE`

The `PURGE` clause completely removes grants created with a specific access method that have already been expired or revoked. In scenarios with very large amount of grants associated with an access method (e.g. when grants are automatically generated), purging inactive grants can improve the performance and experience of auditing grants with the `SHOW` clause. In some very high volume scenarios where grants are created by the hundreds of millions, purging may be necessary to limit the probability of collisions resulting in failure to create new grants. Note that the performance cost of validating a grant is independent from the number of existing grants, regardless of whether they are active or inactive.

Beware that any details associated with purged grants will be permanently lost and will no longer be available for auditing purposes. The `FOR` clause can be used to establish a minimum grace period after which expired or revoked grants should be purged. As with other security-sensitive operations related with the `ACCESS` statement, the purging of grants is logged in the SurrealDB server.

The clause will return the details of all grants that have successfully been purged and its performance will depend on the number of purged grants.

```syntax title="SurrealQL Syntax"
ACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ]
	PURGE [ EXPIRED | REVOKED [ , EXPIRED | REVOKED ] ] [ FOR @duration ]
]
```

#### Example: Purging grants that have been expired

```surql
ACCESS api PURGE EXPIRED;
```

#### Example: Purging grants that have been revoked for more than 90 days

```surql
ACCESS api PURGE REVOKED FOR 90d;
```

#### Example: Purging all grants that have been invalid for more than a year

```surql
ACCESS api PURGE EXPIRED, REVOKED FOR 1y;
```

## Improving error output

To improve the output of an error message inside an `ACCESS` statement, a [`THROW`](/docs/reference/query-language/statements/throw.md) statement can be used.

Follow these steps to see the output in practice.

First, start the SurrealDB server with a root user:

```bash
surreal start --user root --pass secret
```

Log in as the root user, choose the namespace `test` and database `test`, and run the following `DEFINE ACCESS` command.

```surql
DEFINE ACCESS account ON DATABASE TYPE RECORD
    SIGNUP ({
    IF $email = "me@me.com" {
        THROW "That's my email!!!"
    } ELSE {
        CREATE user SET email = $email,
          pass = crypto::argon2::generate($pass)}
    })
    SIGNIN ( SELECT * FROM user WHERE email = $email
      AND crypto::argon2::compare(pass, $pass) )
    DURATION FOR TOKEN 15m, FOR SESSION 12h
;
```

As the `THROW` statement checks for the email address `me@me.com`, this can be tested using CURL at the [`signup`](/docs/reference/rest-api/http-protocol.md#signup) endpoint via the following command.

```bash
curl -X POST -H "Accept: application/json" -d '{"ns":"main","db":"main","ac":"account", "email": "me@me.com", "pass": "strongpassword"}' http://localhost:8000/signup
```

The error output shows the user-defined error message `That's my email!!!`.

```bash title="Output"
{"code":400,"details":"Request problems detected","description":"There is a problem with your request. Refer to the documentation for further information.","information":"There was a problem with the database: An error occurred: That's my email!!!"
```

In all other cases, the signup process will work, returning a token.

```bash
curl -X POST -H "Accept: application/json" -d '{"ns":"main","db":"main","ac":"account", "email": "someotheremail@me.com", "pass": "strongpassword"}' http://localhost:8000/signup
```

```bash title="Output"
{"code":200,"details":"Authentication succeeded","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3NDYwNzIxOTAsIm5iZiI6MTc0NjA3MjE5MCwiZXhwIjoxNzQ2MDczMDkwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiI3YTc0ZjQ5ZS02OWMxLTRiMjMtYmRhNy05YThkNTNjNWFiZmIiLCJOUyI6InRlc3QiLCJEQiI6InRlc3QiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6b2tlZjN5bmI4eXJkd2l3b3h1YjEifQ.4t1xwVkl36PeTFuBj0d41D6A-bwCx7LoNoLlj6yokA8wOKwEa1ldjBzTldZEmylLgP5-q8D4wp6f9Y6ntBZyPA","refresh":null}
```
