DEFINE TOKEN
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 refered 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.
DEFINE TOKEN @name ON [ NAMESPACE | DATABASE | SCOPE @scope ] TYPE @type VALUE @value
With HMAC algorithms (HS256
,HS384
,HS512
) the value of the defined token will be the secret used both to sign and verify the signature of 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 sign the token
TYPE HS512
-- Specify the secret used to sign and verify the authenticity of the token
VALUE "sNSYneezcr8kqphfOC6NwwraUHJCVAt0XjsRSNmssBaBRh3WyMa9TRfq8ST7fsU2H2kGiOpU4GbAF1bCiXmM1b3JGgleBzz7rsrz6VvYEM4q3CLkcO8CMBIlhwhzWmy8"
;
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 sign 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-----"
;
If not specified, the default algorithm used is HS512
.
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 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
, https://surrealdb.com/scope
...
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
, optionallyid
.
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 sign 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.
{
"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 sign 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.
{
"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.
{
"exp": 2147483647,
"tk": "token_name",
"ns": "abcum",
"db": "app_vitalsense",
"sc": "users"
}