SurrealDB Docs Logo

Enter a search query

Authentication

There are multiple forms of authentication built into SurrealDB, supporting different use cases:

  • System users: Created by the SurrealDB administrator and used for managing and consuming the database.
  • Record users: Used for consuming the database within permissions logic, they allow custom signup and signin.

System users

System users is the term we use to describe users defined directly on SurrealDB by the administrator. Same concept as any other database.

Users may belong to different levels (root, namespace or database) and have different roles assigned to limit what they can do to the system. Users are defined with the DEFINE USER statement.

SurrealDB implements RBAC (Role Based Access Control) to define what a user can do. Each user is assigned one or more roles (currently limited to the built-in OWNER, EDITOR and VIEWER roles) and will be allowed to perform an action over a resource as long as at least one of their roles allow it.

Go to DEFINE USER for more information.

Example: Define a Root-level user

Root-level users have visibility into all namespaces and databases, which means that their permissions apply to all of those levels.

In this example we will create a root-level user john with a password and the OWNER role:

DEFINE USER john ON ROOT PASSWORD "VerySecurePassword!" ROLES OWNER;

Sign in using the new user

Examples using the JavaScript SDK or a raw HTTP request.

JavaScript SDK

const db = new Surreal(); db.connect('ws://localhost:8000/rpc', { namespace: 'test', database: 'test', }); db.signin({ username: 'john', password: 'VerySecurePassword!', });

HTTP Request

curl -X POST \ -H "Accept: application/json" \ -d '{"user":"john", "pass":"VerySecurePassword!"}' \ http://localhost:8000/signin

Example: Define a Database-level user

Database-level users have visibility into all resources that belong to the database where the user is defined.

In this example we will create a database-level user mary with a password and the EDITOR role:

DEFINE USER mary ON DATABASE PASSWORD "VerySecurePassword!" ROLES EDITOR;

Sign in using the new user

Examples using the JavaScript SDK or a raw HTTP request.

Notice how we need to pass along NS and DB properties here, to let SurrealDB know where the user is defined.

JavaScript SDK

const db = new Surreal(); db.connect('ws://localhost:8000/rpc', { namespace: 'test', database: 'test', }); db.signin({ // Because we are signin in a database user, we need to let SurrealDB know on which database this user is located. namespace: 'test', database: 'test', username: 'mary', password: 'VerySecurePassword!', });

HTTP Request

curl -X POST \ -H "Accept: application/json" \ -d '{"NS":"test", "DB":"test", "user":"mary", "pass":"VerySecurePassword!"}' \ http://localhost:8000/signin

Record users

Available since: v2.0.0

Record users (called “scope users” before v2.0.0) represent users that are defined as a record in a database instead of through the DEFINE USER statement. Since these users exist as regular database records, they can have associated fields containing any information required for authentication and authorization.

Thanks to this, SurrealDB is able to offer mechanisms to define your own signin and signup logic as well as custom table and field permissions for record users. This feature contributes to making SurrealDB an all-in-one BaaS (Backend-as-a-Service).

Record users are defined with the DEFINE ACCESS statement of TYPE RECORD.

A record access is configured with the following specific clauses:

  • SIGNUP: Defines the logic for when a user signs up as a record user. Usually creates a new record in a table.
  • SIGNIN: Defines the logic for when a user signs in as a record user. Usually checks credentials against table records.

By default, record users have no permissions. They don’t use the Role-Based Access Control (RBAC) system and can only access data if allowed by a PERMISSIONS clause, which is defined on every data resource (i.e. tables and fields) and defaults to NONE.

To learn more about creating a record user, refer to the DEFINE ACCESS … TYPE RECORD documentation.

Example: Setup record authentication

We will go over one of the many ways you can set up record authentication. Given you can define your own logic, there is not a single way to do it. Feel free to modify where needed!

Define the User table and fields

Typically, you would define a user table where new records are created every time a user signs up.

In the following code snippet we will define the user table and a few fields that enforce the following:

  • An authenticated user can select, update and delete its own user record.
  • Asserts that the email provided by the user is actually an email address.
  • Forbid users to use an email that is already in use by another user. We do this by creating a unique index for the email field.
Define tables and fields
DEFINE TABLE user SCHEMAFULL PERMISSIONS FOR select, update, delete WHERE id = $auth.id; DEFINE FIELD name ON user TYPE string; DEFINE FIELD email ON user TYPE string ASSERT string::is::email($value); DEFINE FIELD password ON user TYPE string; DEFINE INDEX email ON user FIELDS email UNIQUE;
Define the User record access

Define the user record access: allow users to signin and signup by using the table and fields defined in the previous step

We will configure the record access like this:

  • The sign in logic needs the email and password parameters to be provided by the user. In the query, we can use them as $email and $password.
  • The sign up logic needs the name, email and password parameters to be provided by the user. In the query, we can use them as $name, $email and $password.
Scope definition
DEFINE ACCESS user ON DATABASE TYPE RECORD SIGNIN ( SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(password, $password) ) SIGNUP ( CREATE user CONTENT { name: $name, email: $email, password: crypto::argon2::generate($password) } );

Sign up as a user record

Now that the record access is defined, we can start using it.

Examples using the JavaScript SDK or a raw HTTP request.

JavaScript SDK

const db = new Surreal(); db.connect('ws://localhost:8000/rpc', { namespace: 'test', database: 'test', }); db.signup({ namespace: 'test', database: 'test', // Provide the name of the access method access: 'user', // Provide the variables used by the signup query variables: { name: 'John Doe', email: 'john@doe.org', password: 'VerySecurePassword!', } });

HTTP Request

curl -X POST \ -H "Accept: application/json" \ -d '{"NS":"test", "DB":"test", "AC":"user", "name":"John Doe", "email":"john@doe.org", "password":"VerySecurePassword!"}' \ http://localhost:8000/signup

Sign in as a record user

Once a user has signed up, it can now sign in when needed.

Examples using the JavaScript SDK or a raw HTTP request.

JavaScript SDK

const db = new Surreal(); db.connect('ws://localhost:8000/rpc', { namespace: 'test', database: 'test', }); db.signin({ namespace: 'test', database: 'test', // Provide the name of the access method access: 'user', // Provide the variables used by the signin query variables: { email: 'john@doe.org', password: 'VerySecurePassword!', } });

HTTP Request

curl -X POST \ -H "Accept: application/json" \ -d '{"NS":"test", "DB":"test", "AC":"user", "email":"john@doe.org", "password":"VerySecurePassword!"}' \ http://localhost:8000/signin

Sessions

Available since: v2.0.0

Whenever authentication is performed with any kind of user against SurrealDB, a session is established between the client and the SurrealDB server with which the connection was established. These sessions exist only in memory on the server for the duration of the connection, whether it is a single request through the HTTP REST API or through multiple requests in the same connection using the WebSocket API and any of the SDKs that leverage it.

Parameters

Certain security-related parameters are automatically set by SurrealDB in the context of a session. These parameters can be referenced in SurrealQL during authentication and authorization.

Session

The $session parameter contains information about the current session. This parameter is set in every SurrealDB session.

In the following example, you can see the result of the SELECT * FROM $session query in an authenticated session for a record user using the HTTP REST API:

{ "ac": "user", "db": "test", "exp": null, "id": "example-client", "ip": "127.0.0.1", "ns": "test", "or": "http://www.example.com", "rd": "user:example", "tk": { "AC": "user", "DB": "test", "ID": "user:example", "NS": "test", "exp": 1723118226, "iat": 1723114626, "iss": "SurrealDB", "jti": "3b3fe74a-955c-46d7-9400-363848912292", "nbf": 1723114626 } }

On the root of the object, you will find the following fields:

  • ip: The IP address that established the connection with SurrealDB.
  • exp: The time at which the session will expire.
    • Will be NONE or null when the session does not expire.
  • ns: The name of the currently selected namespace.
    • Will be NONE or null when no namespace is selected.
  • db: The name of the currently selected database.
    • Will be NONE or null when no database is selected.
  • rd: The record identifier of the currently authenticated record user.
    • Will be NONE or null when unauthenticated or authenticated as a system user.
  • ac: The name of the access method that was used to authenticate.
    • Will be NONE or null when not authenticated with an access method.
  • or: The value of the Origin header of the HTTP request.
    • This header is usually set by browsers to identify the site that originated the request.
  • id: The value of the surreal-id header of the HTTP request.
    • This value can be set by clients to identify their individual sessions to the server.
  • tk: An object containing the claims present in the authentication token used to establish the session.
    • Will be NONE or null when not authenticated.

The values stored in the session parameter can be accessed through the session::* family of functions.

Token

The $token parameter contains the claims contained in the token used to authenticate the current session. This parameter is set in every authenticated SurrealDB session.

In this example, you can see the result of the SELECT * FROM $token query in an authenticated session for a record user:

{ "AC": "user", "DB": "test", "ID": "user:example", "NS": "test", "exp": 1723118226, "iat": 1723114626, "iss": "SurrealDB", "jti": "3b3fe74a-955c-46d7-9400-363848912292", "nbf": 1723114626 }

Whenever authentication is done directly using a token, this object will contain the claims contained in that token.

When that token is issued by SurrealDB after successful authentication, the object will usually contain the following fields:

  • NS: The name of the namespace the user is authenticated in.
    • Will be NONE or null when the user is authenticated at the root level.
  • DB: The name of the database the user is authenticated in.
    • Will be NONE or null when the user is authenticated at the root or namespace level.
  • ID: The record identifier of the currently authenticated record user.
    • Will not be present when not authenticated as a record user.
  • AC: The name of the access method that is used to authenticate.
    • Will be NONE or null when authenticating without an access method.

The following fields correspond to claims defined in the standard JWT implementation described in RFC 7519:

  • iat: The time at which the token was issued.
  • nbf: The time before which the token will not be accepted to establish new authenticated sessions.
  • exp: The time after which the token will not be accepted to establish new authenticated sessions.
  • jti: A unique identifier used to reference the token.
  • iss: A string identifying the entity which issued the token.

Auth

The $auth parameter points to the record belonging to the current authenticated record user. This parameter is set only when the session is authenticated with an existing record user.

When the $auth parameter is set, you can access any of the fields of the record corresponding to the authenticated user (e.g. $auth.name or $auth.email) via that parameter.

Expiration

Authenticated sessions remain valid for a certain duration. This duration is NONE by default, meaning that sessions will not expire unless otherwise specified. This duration can be customised on both the DEFINE USER and DEFINE ACCESS statements to any specific value defining the maximum duration of an authenticated session associated with that user or access method. After the defined duration, the authenticated session will expire. For example, the DEFINE USER example DURATION FOR SESSION 1d clause will ensure that any authenticated sessions for the example user will expire after a day.

Expired sessions can no longer be used to call authenticated methods and doing so will result in a specific error indicating that the session has expired. SurrealQL can be used to check the expiration of the active session by running SELECT exp FROM $session, which show the Unix time when the session will expire or NONE in the case that the session does not expire.

Clients can reuse a connection with an expired session to refresh the session using valid credentials. This includes calling the signin method to obtain a new token with credentials and reauthenticate the session using that token or calling the authenticate method to reauthenticate the session with an existing token.

It is important to note that token duration and session duration are independent concepts. Token duration, which can be similarly customised, refers to the validity of the token (i.e. the value of its exp claim), during which it can be used to establish an authenticated session. Tokens issued by SurrealDB have a default duration of one hour. Token expiration is used to limit the time during which a token can be compromised resulting in unauthorized access; tokens are often stored in the client and could be stolen with attacks like cross-site scripting. Session expiration can be used to ensure that users are required to reauthenticate in order to prove that they still have access to valid credentials as well as to limit the impact of a compromised client with an established session; sessions are stored in memory in the server and cannot be similarly stolen. It is recommended that tokens are configured to last for as little as necessary before being exchanged for an authenticated session, whereas sessions are recommended to last for as little as necessary to allow for the typical client to complete a set of authenticated actions.

© SurrealDB GitHub Discord Community Cloud Features Releases Install