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 tableSIGNIN
: Defines the logic for when a user signs in to the scope. It usually check the provided credentials against the data in a tableSESSION
: 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 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
andpassword
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
andpassword
parameters to be provided by the user. In the scope logic, we can use them as$name
,$email
and$password
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