Skip to main content
Version: 1.x

DEFINE TOKEN statement

SurrealDB can work with third-party authentication providers such as OpenID Connect providers, OAuth providers and other trusted parties providing JWT (JSON Web Tokens, also referred to in this page as “tokens”). Let's say that your provider issues your client (e.g. a user or a service) a JWT once it has authenticated. By using the DEFINE TOKEN statement, you can set the public key or shared secret that will be used to verify the authenticity of the token.

This verification is performed automatically by SurrealDB when provided with a JWT through any of its interfaces (i.e. the HTTP REST API through the “Authorization” header or any of the SDKs through the “Authenticate” methods) before trusting the claims contained in the token and allowing SurrealQL queries to access the values of those claims.

SurrealQL Syntax
DEFINE TOKEN [ IF NOT EXISTS ] @name ON [ NAMESPACE | DATABASE | SCOPE @scope ] TYPE @type VALUE @value [ COMMENT @string ]

Verification Types

When defining a token, its type describes the cryptographic algorithm or specification that will be used to verify the token. This can be an HMAC algorithm, a public-key cryptography algorithm or a remote JWKS object containing all the required information to verify the token. When not specified, the type is defined as the HS256 HMAC cryptographic algorithm.

Hash-Based Message Authentication Code (HMAC)

With HMAC algorithms (HS256,HS384,HS512) the value of the defined token will be the secret used both to sign (by the issuer of the token) and verify (by SurrealDB) the token. Anyone with access to this secret will be able to issue tokens with arbitrary claims which will be trusted by SurrealDB.

The following example shows the definition of a token using an HMAC algorithm.

-- Specify the namespace and database for the token
USE NS abcum DB app_vitalsense;

-- Set the name of the token
DEFINE TOKEN token_name
-- Use this token provider for database authorization
ON DATABASE
-- Specify the cryptographic signature algorithm used to verify the token
TYPE HS512
-- Specify the secret used to sign and verify the authenticity of the token
VALUE "sNSYneezcr8kqphfOC6NwwraUHJCVAt0XjsRSNmssBaBRh3WyMa9TRfq8ST7fsU2H2kGiOpU4GbAF1bCiXmM1b3JGgleBzz7rsrz6VvYEM4q3CLkcO8CMBIlhwhzWmy8"
;

Public-Key Cryptography

With public-key cryptography algorithms (EDDSA, ES256, ES384, ES512, PS256, PS384, PS512, RS256, RS384, RS512) the value of the defined token will be the public key used to verify the signature of the token. This value is not secret and should be provided by the issuer of the tokens. Tokens will be signed using the private key, known only to the issuer. The public key value should be provided to SurrealDB including its header and footer. Any whitespace will be trimmed.

The following example shows the definition of a token using a public-key cryptography algorithm.

-- Specify the namespace and database for the token
USE NS abcum DB app_vitalsense;

-- Set the name of the token
DEFINE TOKEN token_name
-- Use this token provider for database authorization
ON DATABASE
-- Specify the cryptographic signature algorithm used to verify the token
TYPE RS256
-- Specify the public key used to verify the authenticity of the token
VALUE "-----BEGIN PUBLIC KEY-----
MUO52Me9HEB4ZyU+7xmDpnixzA/CUE7kyUuE0b7t38oCh+sQouREqIjLwgHhFdhh3cQAwr6GH07D
ThioYrZL8xATJ3Youyj8C45QnZcGUif5PkpWXDi0HJSoMFekbW6Pr4xuqIqb2LGxGDVJcLZwJ2AS
Gtu2UAfPXbBD3ffiad393M22g1iHM80YaNi+xgswG7qtXE4lR/Lt4s0MeKKX7stdWI1VIsoB+y3i
r/OWUvJPjjDNbAsyy8tQmxydv+FUnLEP9TNT4AhN4DXcJ+XsDtW7OWt4EdSVDeKpGbIMvIrh1Pe+
Nilj8UHNyNDHa2AjK3seMo6CMvaIQJKj5o4xGFblFGwvvPD03SbuQLs1FdRjsZCeWLdYeQ3JDHE9
sFG7DCXlpMJcaYT1mf4XHJ0gPekNLQyewTY3Vxf7FgV3GCNjV20kcDFgJA2+iVW2wSrb+txD1ycE
kbi8jh0pedWwE40VQWaTh/8eAvX7IHWya/AEro25mq+m6vktNZLbvLphhp586kJK3Tdt3YjpkPre
M3nkFWOWurIyKbtIV9JemfwCgt89sNV45dTlnEDEZFFGnIgDnWgx3CUo4XmhICEQU8+tklw9jJYx
iCTjhbIDEBHySSSc/pQ4ftHQmhToTlQeOdEy4LYiaEIgl1X+hzRH1hBYvWlNKe4EY1nMCKcjgt0=
-----END PUBLIC KEY-----"
;

JSON Web Key Set (JWKS) Since 1.2.0

With JWKS, a set of JWK (JSON Web Key) objects will be dynamically fetched from a remote location and used to verify tokens following the RFC 7517 specification. When defining a JWKS token verification method, its value should contain a valid URL that is reachable by SurrealDB and allowed by the configured network capabilities. This URL should point to a valid JWKS object (as described in Section 5 of RFC 7517) in the form of a JSON document. This is the recommended method to integrate with authentication providers that support JWKS. Providers like Google, AWS Cognito, Azure Active Directory, Auth0, Keycloak or OneLogin provide JWKS endpoints to verify tokens issued by their services.

The following example shows the definition of a token using a JWKS.

-- Specify the namespace and database for the token
USE NS abcum DB app_vitalsense;

-- Set the name of the token
DEFINE TOKEN token_name
-- Use this token provider for database authorization
ON DATABASE
-- Specify the JWKS specification used to verify the token
TYPE JWKS
-- Specify the URL where the JWKS object can be found
VALUE "https://example.com/.well-known/jwks.json"
;

Validating tokens generated by third-party authentication providers using JWKS ensures that keys can be revoked directly from the third-party service and will no longer be accepted by SurrealDB after the local cache for those keys expires. Likewise, it ensures that token verification will not break if keys are rotated, as any new keys will be automatically fetched from the authentication provider if a JWT is received containing a new key identifier in its kid header.

To avoid performing requests to the remote URL for each token that is verified, SurrealDB caches every JWKS object that it pulls for a period of 12 hours. The cache can be purged earlier (e.g. in the event a key is compromised) by restarting the SurrealDB server. If a JWT is received containing a reference to a new key identifier in its kid header, the JWKS object will be fetched again and updated in the cache if the key identifier is found in the remote JWKS object; this operation will only be performed once every 5 minutes to prevent malicious actors from abusing this process to perform denial of service.

Requirements

  • To DEFINE TOKEN ... ON NAMESPACE ... you must have root or namespace level access.
  • To DEFINE TOKEN ... ON DATABASE ... you must have root, namespace, or database level access.
  • To DEFINE TOKEN ... ON SCOPE ... you must have root, namespace, or database level access.
  • You must select your namespace and/or database before you can use the DEFINE DATABASE statement for database or namespace tokens.

Using IF NOT EXISTS clause Since 1.3.0

The IF NOT EXISTS clause can be used to define a token only if it does not already exist. If the token already exists, the DEFINE TOKEN statement will return an error.

-- Create a TOKEN if it does not already exist
DEFINE TOKEN IF NOT EXISTS example ON SCOPE example TYPE HS512 VALUE "example";

Using Tokens

The DEFINE TOKEN statement lets you specify the amount of permission granting authority you want to give to a token issuer. You are able to specify if the provider can grant namespace, database, or scope level access to token holders. For this to work, the JWT issued to be used with SurrealDB must contain claims to specify which namespace, database or scope the token bearer is authorized to act on.

The following claims should be added to the JWT payload by the issuer of the token:

  • exp: The token expiration Unix time. The token will not be valid after.
  • tk: The name that you chose when defining the token.
  • ns: The namespace that the token is issued for.
  • db: The database that the token is issued for.
  • sc: The scope that the token is issued for.

The names of these claims can be in all lowercase (i.e. tk) or all uppercase (i.e. TK), and can be optionally prefaced with the https://surrealdb.com namespace (e.g. https://surrealdb.com/tk) in order to separate claims directed to SurrealDB from claims directed to other services. When using a namespace, the claim name can also be used without abbreviation, such as in https://surrealdb.com/token or https://surrealdb.com/scope. Even when present in the token with a namespace prefix, SurrealDB claims are directly accessible via the $token parameter (e.g. $token.sc), whereas custom claims will need to include the namespace prefix (e.g. $token['https://surrealdb.com/pet_name']) to be accessed in the same way.

The following optional claims are also processed by SurrealDB:

  • id: The identifier of the resource (e.g. user) associated with the token.
  • nbf: The token acceptance Unix time. The token will not be valid before.

The expected claims depend on the level at which the token was defined:

  • For tokens defined ON NAMESPACE: exp, tk, ns.
  • For tokens defined ON DATABASE: exp, tk,ns,db.
  • For tokens defined ON SCOPE: exp, tk, ns,db, sc, optionally id.

For tokens defined ON NAMESPACE and ON DATABASE, the optional rl claim containing an array of capitalized system user roles (e.g. ["Viewer", "Editor", "Owner"]) can be provided. Doing so will apply the access policy for those roles to any action made using the token. By default, tokens without the rl claim will only have the Viewer role.

When calling any of the SurrealDB interfaces using a JWT, SurrealQL queries will gain access to the claims in the token through the $token variable. For example, if the token contains custom claims such as “name” or “email”, the values of those claims will be accessible through $token.name and $token.email.

Additionally, when the id claim is present in the token, the fields of the record matching the identifier specified will be accessible through the $auth variable. For example, if the value of the id claim is user:73q1bl039y6k8z80v55d, and user records have fields such as “name” or “email”, then $auth.name and $auth.email can be used to access those values for the user:73q1bl039y6k8z80v55d record specifically, without them being present in the JWT.

The signature of the token is verified with method defined when creating the token. If the signature of the token is invalid, calls to SurrealDB interfaces using that token will fail.

Namespace

Namespace tokens can be used to select, create, update, and delete on all tables in all databases, as well as to define and remove databases and tables from the namespace.

-- Specify the namespace for the token
USE NS abcum;

-- Set the name of the token
DEFINE TOKEN token_name
-- Use this OAuth provider for namespace authorization
ON NAMESPACE
-- Specify the cryptographic signature algorithm used to verify the token
TYPE HS512
-- Specify the public key so we can verify the authenticity of the token
VALUE "sNSYneezcr8kqphfOC6NwwraUHJCVAt0XjsRSNmssBaBRh3WyMa9TRfq8ST7fsU2H2kGiOpU4GbAF1bCiXmM1b3JGgleBzz7rsrz6VvYEM4q3CLkcO8CMBIlhwhzWmy8"
;

The namespace token payload should at least include the following claims when used to authenticate with SurrealDB.

JWT Payload
{
"exp": 2147483647,
"tk": "token_name",
"ns": "abcum"
}

Database

Database tokens can be used to select, create, update, and delete on all tables in a specific database, as well as to define and remove tables from the database.

-- Specify the namespace and database for the token
USE NS abcum DB app_vitalsense;

-- Set the name of the token
DEFINE TOKEN token_name
-- Use this OAuth provider for database authorization
ON DATABASE
-- Specify the cryptographic signature algorithm used to verify the token
TYPE HS512
-- Specify the public key so we can verify the authenticity of the token
VALUE "sNSYneezcr8kqphfOC6NwwraUHJCVAt0XjsRSNmssBaBRh3WyMa9TRfq8ST7fsU2H2kGiOpU4GbAF1bCiXmM1b3JGgleBzz7rsrz6VvYEM4q3CLkcO8CMBIlhwhzWmy8"
;

The database token payload should at least include the following claims when used to authenticate with SurrealDB.

JWT Payload
{
"exp": 2147483647,
"tk": "token_name",
"ns": "abcum",
"db": "app_vitalsense"
}

Scope

Since the origin of the claims in the JWT is verified, those claims can be used within SurrealQL in the context of a scope in order to provide table and field authorization through an external authenticator using OpenID Connect, OAuth or simply acting as a trusted issuer of a JWT.

This can be done by leveraging table permissions to allow or disallow access depending on the values of the claims in the verified token. For example, these claims can be compared with the records in a table to only return those matching certain criteria.

The scope for which the token was issued will be accessible to SurrealQL through the $scope variable, corresponding to the contents of the sc claim. External authorization providers may provide additional scopes that will not be accessible in this way, and instead should be accessed as any other claim through the $token variable.

Bear in mind that table and field permissions only apply to scope level tokens Access provided by namespace and database tokens is above table-level permissions. When application users will be the ones directly authenticating with JWT, scope tokens are most likely the right choice.

The following example shows how scope tokens can be used to grant authorization by verifying that the “email” claim in the token matches the email used as the index of a user table:

-- Specify the namespace and database for the token
USE NS abcum DB app_vitalsense;

-- Necessary in order to define a scope token
DEFINE SCOPE users;

DEFINE TOKEN token_name ON SCOPE users TYPE RS256 VALUE "-----BEGIN PUBLIC KEY-----
MUO52Me9HEB4ZyU+7xmDpnixzA/CUE7kyUuE0b7t38oCh+sQouREqIjLwgHhFdhh3cQAwr6GH07D
ThioYrZL8xATJ3Youyj8C45QnZcGUif5PkpWXDi0HJSoMFekbW6Pr4xuqIqb2LGxGDVJcLZwJ2AS
Gtu2UAfPXbBD3ffiad393M22g1iHM80YaNi+xgswG7qtXE4lR/Lt4s0MeKKX7stdWI1VIsoB+y3i
r/OWUvJPjjDNbAsyy8tQmxydv+FUnLEP9TNT4AhN4DXcJ+XsDtW7OWt4EdSVDeKpGbIMvIrh1Pe+
Nilj8UHNyNDHa2AjK3seMo6CMvaIQJKj5o4xGFblFGwvvPD03SbuQLs1FdRjsZCeWLdYeQ3JDHE9
sFG7DCXlpMJcaYT1mf4XHJ0gPekNLQyewTY3Vxf7FgV3GCNjV20kcDFgJA2+iVW2wSrb+txD1ycE
kbi8jh0pedWwE40VQWaTh/8eAvX7IHWya/AEro25mq+m6vktNZLbvLphhp586kJK3Tdt3YjpkPre
M3nkFWOWurIyKbtIV9JemfwCgt89sNV45dTlnEDEZFFGnIgDnWgx3CUo4XmhICEQU8+tklw9jJYx
iCTjhbIDEBHySSSc/pQ4ftHQmhToTlQeOdEy4LYiaEIgl1X+hzRH1hBYvWlNKe4EY1nMCKcjgt0=
-----END PUBLIC KEY-----";

DEFINE TABLE user SCHEMAFULL
-- Authorized users can select, update, delete and create user records
PERMISSIONS FOR select, update, delete, create
-- The current scope must be "users"
WHERE $scope = "users"
-- The email of the user being queried must match the email claim in the token
-- Only matching records will be changed or returned
AND email = $token.email
;

DEFINE INDEX email ON user FIELDS email UNIQUE;
DEFINE FIELD email ON user TYPE string ASSERT string::is::email($value);
DEFINE FIELD name ON user TYPE string;
DEFINE FIELD nickname ON user TYPE string;
DEFINE FIELD picture ON user TYPE string;

You may also use permissions clauses to perform additional verification on other JWT claims (e.g. verifying that the iss claim matches a specific principal using $token.iss) that may be required or recommended by a the provider of the token.

The scope token payload should at least include the following claims when used to authenticate with SurrealDB.

JWT Payload
{
"exp": 2147483647,
"tk": "token_name",
"ns": "abcum",
"db": "app_vitalsense",
"sc": "users"
}