The authentication component enables password-protected access to your SQLPage pages. It provides flexible authentication options including HTTP basic auth, custom login forms, and session token management.
The authentication component must be placed at the very top of your SQL file, before any other component. Once page content is sent to the browser, it’s too late to restrict access.
Authentication Options
SQLPage offers two main authentication approaches:
-
Authentication component: Self-managed usernames and passwords
- No external dependencies
- Full control over login forms, session duration, and permissions
- Requires password hash management
-
Single sign-on (SSO): Use existing identity providers
- Google, Microsoft, or organizational OAuth/OIDC providers
- No password management required
- See SSO documentation for setup
HTTP Basic Authentication
The simplest authentication method uses browser popups:
SELECT 'authentication' AS component,
'$argon2i$v=19$m=8,t=1,p=1$YWFhYWFhYWE$oKBq5E8XFTHO2w' AS password_hash,
sqlpage.basic_auth_password() AS password;
The password hash above corresponds to the password “password”. Generate your own using sqlpage.hash_password().
Multiple Users with Basic Auth
Handle different users with a CASE statement:
SELECT 'authentication' AS component,
CASE sqlpage.basic_auth_username()
WHEN 'admin' THEN '$argon2i$v=19$m=8,t=1,p=1$YWFhYWFhYWE$oKBq5E8XFTHO2w'
WHEN 'user' THEN '$argon2i$v=19$m=8,t=1,p=1$YWFhYWFhYWE$qsrWdjgl96ooYw'
END AS password_hash,
sqlpage.basic_auth_password() AS password;
Or query from a database:
SELECT 'authentication' AS component,
(SELECT password_hash FROM users WHERE username = sqlpage.basic_auth_username()) AS password_hash,
sqlpage.basic_auth_password() AS password;
For better user experience, create custom login forms instead of browser popups.
login.sql
SELECT 'login' AS component;
protected_page.sql
SELECT 'authentication' AS component,
'login.sql' AS link,
(SELECT password_hash FROM users WHERE username = :username) AS password_hash,
:password AS password;
-- Code below only executes if authentication succeeds
SELECT 'shell' AS component, 'Protected Page' AS title;
SELECT 'text' AS component, 'Welcome! You are authenticated.' AS contents;
If authentication fails, the user is redirected to login.sql.
Session Token Management
Password hashing is computationally expensive by design (to prevent brute-force attacks). For better performance, use session tokens instead of validating passwords on every page.
Create Session on Login
create_session.sql
SELECT 'authentication' AS component,
'login.sql' AS link,
(SELECT password_hash FROM users WHERE username = :username) AS password_hash,
:password AS password;
-- Authentication succeeded, create session token
INSERT INTO sessions (token, username, created_at, expires_at)
VALUES (
sqlpage.random_string(32),
:username,
CURRENT_TIMESTAMP,
datetime('now', '+7 days')
)
RETURNING
'cookie' AS component,
'session_token' AS name,
token AS value,
expires_at AS expires;
SELECT 'redirect' AS component, 'dashboard.sql' AS link;
Validate Session Token
protected_page.sql
-- Check if session token is valid
SELECT 'redirect' AS component, 'login.sql' AS link
WHERE NOT EXISTS (
SELECT 1 FROM sessions
WHERE token = sqlpage.cookie('session_token')
AND expires_at > CURRENT_TIMESTAMP
);
-- Token is valid, show protected content
SELECT 'shell' AS component, 'Dashboard' AS title;
Create Sessions Table
CREATE TABLE sessions (
token TEXT PRIMARY KEY,
username TEXT NOT NULL,
created_at TIMESTAMP NOT NULL,
expires_at TIMESTAMP NOT NULL,
FOREIGN KEY (username) REFERENCES users(username)
);
CREATE INDEX idx_sessions_expires ON sessions(expires_at);
Password Hashing
Always store password hashes, never plain passwords:
-- Generate hash for a new user
INSERT INTO users (username, password_hash)
VALUES (
:username,
sqlpage.hash_password(:password)
);
You can also generate hashes using online tools like argon2.online.
Advanced: Role-Based Access
Implement different permission levels:
SELECT 'authentication' AS component,
'login.sql' AS link,
(SELECT password_hash FROM users WHERE username = :username) AS password_hash,
:password AS password;
-- Check user role
SET role = (SELECT role FROM users WHERE username = :username);
SELECT 'redirect' AS component, 'access_denied.sql' AS link
WHERE $role != 'admin';
-- Admin-only content below
SELECT 'shell' AS component, 'Admin Panel' AS title;
Logout Functionality
logout.sql
-- Delete session from database
DELETE FROM sessions WHERE token = sqlpage.cookie('session_token');
-- Clear cookie
SELECT 'cookie' AS component,
'session_token' AS name,
'' AS value,
datetime('now', '-1 day') AS expires;
SELECT 'redirect' AS component, 'login.sql' AS link;
Top-level Parameters
URL to redirect users who are not authenticated. If omitted, uses HTTP basic authentication with a browser popup.
The password submitted by the user. Typically set to :password from a login form or sqlpage.basic_auth_password() for basic auth.
The stored password hash to validate against. Use sqlpage.hash_password() to generate hashes. Use the Argon2 format.
Security Best Practices
Use Strong Password Hashing
SQLPage uses Argon2, a modern and secure hashing algorithm. Always use sqlpage.hash_password() to generate hashes:
SELECT sqlpage.hash_password('user_password_here');
Implement Session Expiration
Automatically clean up expired sessions:
DELETE FROM sessions WHERE expires_at < CURRENT_TIMESTAMP;
Run this periodically or add it to frequently accessed pages.
Use HTTPS
Always use HTTPS in production to encrypt credentials in transit. Configure your web server or use SQLPage’s built-in HTTPS support.
Rate Limiting
Prevent brute-force attacks by tracking failed login attempts:
CREATE TABLE login_attempts (
username TEXT,
attempt_time TIMESTAMP,
ip_address TEXT
);
-- Block users with too many failed attempts
SELECT 'redirect' AS component, 'too_many_attempts.sql' AS link
WHERE (
SELECT COUNT(*) FROM login_attempts
WHERE username = :username
AND attempt_time > datetime('now', '-15 minutes')
) >= 5;
Complete Login Example
Here’s a full working example:
users table
CREATE TABLE users (
username TEXT PRIMARY KEY,
password_hash TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO users (username, password_hash)
VALUES ('admin', sqlpage.hash_password('admin123'));
login.sql
SELECT 'form' AS component, 'create_session.sql' AS action, 'Login' AS title;
SELECT 'username' AS name, 'text' AS type, TRUE AS required;
SELECT 'password' AS name, 'password' AS type, TRUE AS required;
create_session.sql
SELECT 'authentication' AS component,
'login.sql' AS link,
(SELECT password_hash FROM users WHERE username = :username) AS password_hash,
:password AS password;
INSERT INTO sessions (token, username, expires_at)
VALUES (
sqlpage.random_string(32),
:username,
datetime('now', '+7 days')
)
RETURNING
'cookie' AS component,
'session_token' AS name,
token AS value;
SELECT 'redirect' AS component, 'dashboard.sql' AS link;
dashboard.sql
SELECT 'redirect' AS component, 'login.sql' AS link
WHERE NOT EXISTS (
SELECT 1 FROM sessions
WHERE token = sqlpage.cookie('session_token')
AND expires_at > CURRENT_TIMESTAMP
);
SELECT 'shell' AS component, 'Dashboard' AS title;
SELECT 'text' AS component, 'Welcome to your dashboard!' AS contents;