DEFINE SCOPE (Auth Scopes Overview)
DEFINE SCOPE (Auth Scopes Overview)
Level 4 — Schema Definition & Constraints The DDL (Data Definition Language) statement in SurrealDB used to configure client authentication scopes, defining session token durations (
SESSION), custom registration queries (SIGNUP), and login verification queries (SIGNIN) directly at the database layer.
1. Prerequisites
DEFINE TABLE— The user table context.- Namespace & Database — The execution boundaries.
2. Term Category
Authentication & Permissions (auth scope & access definition): - Database Command / Tool
3. Explanation
(1) Design Motivation — "Why did we design this?"
In traditional web architectures:
- The client browser connects to a backend API server (Node.js, Python).
- The backend server manages user sessions, queries the database, and returns data.
- This middleman layer exists because databases cannot authorize user permissions safely: giving a client direct access to PostgreSQL exposes the entire database.
We designed the DEFINE SCOPE statement in SurrealDB to eliminate this backend API middleman.
Scopes define authentication zones directly inside the database.
By writing signup and signin query scripts inside a scope, SurrealDB handles user registration, password validation, and JWT generation natively.
The client connects directly to SurrealDB via WebSockets, authenticates against a scope, and queries data safely, restricted by the table's row-level permissions.
(2) Key Scope Attributes
SESSION <duration>: Sets the expiration time for the client's JWT auth token (e.g.SESSION 24h).SIGNUP <query>: The SurrealQL query that runs when a client signs up. It creates a record in theusertable and hashes their password.SIGNIN <query>: The query that runs when a user attempts to log in. It compares input details against the database and validates passwords.- The
$authVariable: Once authenticated, the user's record is bound to the$authvariable, which is referenced in row permissions (e.g.WHERE id = $auth.id).
(3) Reality Metaphor (Hotel Check-in Kiosks)
Imagine guest access in a secure hotel:
- Traditional API: A tourist booking rooms through a Travel Agent.
- The agent checks availability, collects details, books the room, and hands over a key.
- The guest never speaks directly to the hotel management.
DEFINE SCOPE(Direct Web): A Self-Service Check-in Kiosk in the lobby.SIGNUP(Registration): You type your name and scan your passport. The machine registers you.SIGNIN(Verification): You type your PIN. The machine prints a magnetic Key Card (JWT) with your name on the chip ($auth).- You swipe this card directly at the elevator and room doors (row permissions) to gain access without asking the clerk.
(4) Code Examples
Defining Auth Scopes in SurrealQL
Let's build a client authentication scope:
DEFINE TABLE user SCHEMAFULL;
DEFINE FIELD email ON user TYPE string;
DEFINE FIELD password ON user TYPE string;
-- Define the authentication scope
DEFINE SCOPE user_scope
SESSION 24h
-- Signup logic (creates user and hashes password using Argon2)
SIGNUP (
CREATE user SET
email = $email,
password = crypto::argon2::generate($password)
)
-- Signin logic (verifies email and validates password hash)
SIGNIN (
SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(password, $password)
);
4. Common Mistakes & Pitfalls
Mistake 1: Storing raw text passwords or using basic string comparisons in signin scripts, creating security vulnerabilities
The mistake: Writing a scope signin query as SELECT * FROM user WHERE email = $email AND password = $password; without password hashing comparison functions.
Why it's wrong: Storing and comparing passwords in raw text exposes user credentials to SQL injections and database leaks.
SurrealDB's type validations require secure cryptographic helpers to verify hashed passwords.
Fix: Always use the built-in crypto::argon2::generate() on signup and crypto::argon2::compare() on signin to secure user credentials:
-- CORRECT SIGNIN PASSWORD CHECK
SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(password, $password);
Mistake 2: Defining Access Scopes Without Password Hashing Assertions
The mistake: Storing raw plain-text passwords in SIGNUP scope queries.
Why it's wrong: Scope signup handlers MUST hash passwords using crypto::argon2::generate($pass) before storing user records.
Incorrect:
DEFINE ACCESS user ON DATABASE TYPE RECORD SIGNUP (CREATE user SET pass = $pass); // ❌ Plain-text password!
Fix:
DEFINE ACCESS user ON DATABASE TYPE RECORD SIGNUP (CREATE user SET pass = crypto::argon2::generate($pass));
Mistake 3: Comparing Passwords in SIGNIN Scopes Without Argon2 Verification
The mistake: Comparing $pass = pass in SIGNIN handlers when passwords were stored as Argon2 hashes.
Why it's wrong: Argon2 hashes must be verified using crypto::argon2::compare(pass, $pass).
Incorrect:
-- Comparing plain-text $pass to hash
DEFINE ACCESS user ... SIGNIN (SELECT * FROM user WHERE email = $email AND pass = $pass); // ❌ Fails!
Fix:
DEFINE ACCESS user ... SIGNIN (SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(pass, $pass));
5. Practice Exercises
Exercise 1: RECORD Access Method Definition (SurrealDB 2.x)
Scenario:
Define a scoped user access method user_access for web clients authenticating against table user using DEFINE ACCESS.
Requirements:
- Define access method
user_accessON DATABASE TYPE RECORD. - Specify
SIGNINquery authenticating username and password.
Answer
Implementation
DEFINE ACCESS user_access ON DATABASE TYPE RECORD
SIGNIN (
SELECT * FROM user
WHERE username = $username AND crypto::argon2::compare(password, $pass)
);
Technical Explanation
DEFINE ACCESS ... TYPE RECORDestablishes client authentication scopes in SurrealDB 2.x (replacing legacy 1.xDEFINE SCOPE).SIGNINexecutes a query validating user credentials and issuing a scoped JWT session token.- Enables direct browser-to-database authentication without custom API backend middleware.
Exercise 2: JWT Access Scope Definition
Scenario:
Configure external JWT authentication jwt_access allowing third-party auth providers (like Auth0 or Clerk) to issue valid access tokens.
Requirements:
- Define access method
jwt_accessON DATABASE TYPE JWT. - Specify algorithm
HS256and secret key"SuperSecretKey123!".
Answer
Implementation
DEFINE ACCESS jwt_access ON DATABASE TYPE JWT
ALGORITHM HS256
KEY "SuperSecretKey123!";
Technical Explanation
TYPE JWTallows SurrealDB to validate externally signed JSON Web Tokens.KEYspecifies the cryptographic secret or public key used to verify token signatures.- Integrates external OAuth/OIDC identity providers with SurrealDB row-level security.
Exercise 3: Testing Access Token Session Variables
Scenario:
Inspect the $auth context variable available to scoped client sessions after successful authentication.
Requirements:
- Write a SurrealQL query projecting
$auth.idand$auth.role.
Answer
Implementation
SELECT $auth.id AS current_user, $auth.role AS current_role;
Technical Explanation
$authholds the authenticated user record document context during active client sessions.- Used inside table
PERMISSIONSclauses (PERMISSIONS FOR select WHERE id = $auth.id). - Enforces user-level security boundaries dynamically across queries.
6. Related Terms
7. Key Takeaways
DEFINE SCOPEconfigures native client authentication inside SurrealDB.- Bypasses the need for backend API servers for simple user signups and logins.
SESSIONdefines JWT token expiration intervals (e.g.24h,30d).SIGNUPexecutes registration scripts;SIGNINverifies credentials.- Always use namespaced functions like
crypto::argon2::*to hash and compare passwords. - Validated connections return a JWT token, binding the user's ID to
$auth. - Row permissions check
$auth.idto secure data access for direct client queries.