Skip to main content
Version: 1.2.x

Authentication

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
  • Scope users: Used for consuming the database, and they allow custom signup, signin and permissions logic

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).

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', {
ns: 'test',
db: 'test',
});

db.signin({
user: 'john',
pass: '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', {
ns: 'test',
db: 'test',
});

db.signin({
// Because we are signin in a database user, we need to let SurrealDB know on which database this user is located.
NS: 'test',
DB: 'test',

user: 'mary',
pass: 'VerySecurePassword!',
});

HTTP Request

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

Scope users

Scope is the term we use to describe the mechanism SurrealDB offers to define your own signin and signup logic. This feature contributes to making SurrealDB an all-in-one BaaS (Backend-as-a-Service).

Scopes are defined with the DEFINE SCOPE statement. A scope is configured with the following config:

  • SIGNUP: Defines the logic for when a user signs up to the scope. It usually creates a new entry to a table
  • SIGNIN: Defines the logic for when a user signs in to the scope. It usually check the provided credentials against the data in a table
  • SESSION: Defines the session duration

By default, scopes have no permissions. They don't use the RBAC system and can only view data if allowed by a PERMISSIONS clause, which is defined on every data resource (i.e. tables)

Go to DEFINE SCOPE for more information.

Example: Setup scope authentication

We will go over one of the many ways you can set up scope 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 scope

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

The scope is configured like this:

  • Session tokens expire in 1 day. When a user signs up or signs in, a new session token is created.
  • The sign in logic needs the email and password parameters to be provided by the user. In the scope logic, we 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 scope logic, we can use them as $name, $email and $password
Scope definition
DEFINE SCOPE user SESSION 1d
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 to the scope

Now that the scope 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', {
ns: 'test',
db: 'test',
});

db.signup({
NS: 'test',
DB: 'test',

// Provide the name of the scope
SC: 'user',

// Provide the variables used by the signup query
name: 'John Doe',
email: 'john@doe.org',
password: 'VerySecurePassword!',
});

HTTP Request

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

Sign in to the scope

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', {
ns: 'test',
db: 'test',
});

db.signin({
NS: 'test',
DB: 'test',

// Provide the name of the scope
SC: 'user',

// Provide the variables used by the signin query
email: 'john@doe.org',
password: 'VerySecurePassword!',
});

HTTP Request

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