ACCESS
statementAvailable since: v2.2.0
CautionCurrently, 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. To enable this and other experimental features related to bearer access, set theSURREAL_EXPERIMENTAL_BEARER_ACCESS
environment variable totrue
.
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
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
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.
SurrealQL SyntaxACCESS @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 or record user. 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.
SurrealQL SyntaxACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ] GRANT [ FOR USER @name | FOR RECORD @record ]
-- 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;
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' }
-- 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;
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]
.
SurrealQL SyntaxACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ] SHOW [ GRANT @id | ALL | WHERE @expression ]
-- 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;
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' }
ACCESS api SHOW GRANT JdvDFKMCVYoM;
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' }
Since the subject
attribute of grants associated with a record is a record identifier, it can be used as a record link 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.
-- 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;
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' }
ACCESS api SHOW WHERE subject.record.name = "tobie";
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.
SurrealQL SyntaxACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ] REVOKE [ GRANT @id | ALL | WHERE @expression ] ]
-- 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;
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' }
ACCESS api REVOKE GRANT NJ2I2d7OXxN9;
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' } ] ]
Since the subject
attribute of grants associated with a record is a record identifier, it can be used as a record link 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.
-- 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;
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' }
ACCESS api REVOKE WHERE subject.record.name = "tobie";
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.
SurrealQL SyntaxACCESS @name [ ON [ ROOT | NAMESPACE | DATABASE ] ] PURGE [ EXPIRED | REVOKED [ , EXPIRED | REVOKED ] ] [ FOR @duration ] ]
ACCESS api PURGE EXPIRED;
ACCESS api PURGE REVOKED FOR 90d;
ACCESS api PURGE EXPIRED, REVOKED FOR 1y;
To improve the output of an error message inside an ACCESS
statement, a THROW
statement can be used.
Follow these steps to see the output in practice.
First, start the SurrealDB server with a root user:
surreal start --user root --pass root
Log in as the root user, choose the namespace test
and database test
, and run the following DEFINE ACCESS
command.
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
endpoint via the following command.
curl -X POST -H "Accept: application/json" -d '{"ns":"test","db":"test","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!!!
.
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.
curl -X POST -H "Accept: application/json" -d '{"ns":"test","db":"test","ac":"account", "email": "someotheremail@me.com", "pass": "strongpassword"}' http://localhost:8000/signup
Output{"code":200,"details":"Authentication succeeded","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3NDYwNzIxOTAsIm5iZiI6MTc0NjA3MjE5MCwiZXhwIjoxNzQ2MDczMDkwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiI3YTc0ZjQ5ZS02OWMxLTRiMjMtYmRhNy05YThkNTNjNWFiZmIiLCJOUyI6InRlc3QiLCJEQiI6InRlc3QiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6b2tlZjN5bmI4eXJkd2l3b3h1YjEifQ.4t1xwVkl36PeTFuBj0d41D6A-bwCx7LoNoLlj6yokA8wOKwEa1ldjBzTldZEmylLgP5-q8D4wp6f9Y6ntBZyPA","refresh":null}