This guide provides a comprehensive overview of the authentication system in the Boundary Framework. Boundary provides a robust, production-ready authentication system out of the box, including JWT-based authentication, session management, and Multi-Factor Authentication (MFA).
Boundary's authentication system is built on the Functional Core / Imperative Shell (FC/IS) architecture, ensuring that security logic is pure, testable, and separated from side effects like database access and token signing.
boundary/user: The primary library for authentication, user management, and MFA.Boundary follows a multi-layered security approach:
bcrypt with SHA-512 for salted hashing.JWT_SECRET) and have configurable expiration times.JWT (JSON Web Token) is the primary method for authenticating API requests.
Users can be registered via the API or the web UI. During registration, the password is validated against the configured password policy and hashed before storage.
API Example: Registration
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecureP@ss123!",
"name": "Jane Doe",
"role": "user"
}'
Response (201 Created):
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"email": "user@example.com",
"name": "Jane Doe",
"role": "user",
"active": true,
"createdAt": "2026-01-26T10:00:00Z"
}
The login process authenticates credentials and returns both a JWT token (for API access) and a Session ID.
API Example: Login
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecureP@ss123!"
}'
Response (200 OK):
{
"success": true,
"jwt-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"session-id": "550e8400-e29b-41d4-a716-446655440000",
"user": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"email": "user@example.com",
"name": "Jane Doe",
"role": "user",
"mfa-enabled": false
}
}
HS256 with the JWT_SECRET environment variable.sub (user ID), email, role, iat (issued at), and exp (expiration).:jwt-expiration-hours.Boundary implements stateful session management to provide features that stateless JWTs cannot easily support.
Logging out invalidates the session in the database, rendering the corresponding JWT/Session Token useless for future requests.
API Example: Logout
curl -X DELETE http://localhost:3000/api/sessions/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Boundary supports TOTP-based Multi-Factor Authentication for enhanced account security.
API Example: Initiate Setup
curl -X POST http://localhost:3000/api/auth/mfa/setup \
-H "Authorization: Bearer <jwt-token>"
Response:
{
"secret": "JBSWY3DPEHPK3PXP",
"qrCodeUrl": "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=...",
"backupCodes": ["3LTW-XRM1-GYVF", "CN2K-1AWR-GDVT", ...],
"issuer": "Boundary Framework",
"accountName": "user@example.com"
}
Once MFA is enabled, the login flow becomes a two-step process:
{"requires-mfa?": true}.mfa-code.API Example: Login Step 2
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecureP@ss123!",
"mfa-code": "123456"
}'
Boundary generates 10 single-use backup codes during setup. These codes allow users to regain access if they lose their authenticator device.
XXXX-XXXX-XXXX (e.g., 3LTW-XRM1-GYVF)mfa-code field during login.For more details, see the MFA Setup Guide and MFA API Reference.
Boundary uses a simple but effective role-based access control system.
:admin: Full access to all users and system settings.:user: Standard access to their own profile and resources.:viewer: Read-only access to assigned resources.Roles are enforced via HTTP interceptors:
;; Example route definition with role enforcement
{:path "/api/users"
:methods {:post {:handler (create-user-handler user-service)
:interceptors ['boundary.user.shell.http-interceptors/require-admin]}}}
To maintain a secure Boundary application, follow these guidelines:
HttpOnly, Secure, and SameSite=Strict flags./api/auth/login, /api/auth/mfa/*).JWT_SECRET. Note that this will invalidate all existing sessions.curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"email": "dev@example.com", "password": "Password123!", "name": "Developer", "role": "user"}'
curl -i -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "dev@example.com", "password": "Password123!"}'
Take note of the jwt-token in the response.
curl -X POST http://localhost:3000/api/auth/mfa/setup \
-H "Authorization: Bearer <your-jwt-token>"
curl -X POST http://localhost:3000/api/auth/mfa/enable \
-H "Authorization: Bearer <your-jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"secret": "THE_SECRET_FROM_SETUP",
"backupCodes": ["CODE1", "CODE2", ...],
"verificationCode": "123456"
}'
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "dev@example.com", "password": "Password123!", "mfa-code": "654321"}'
| Error | Cause | Solution |
|---|---|---|
Invalid credentials | Wrong email or password. | Check spelling; use password reset if available. |
MFA code required | MFA is enabled for this user. | Provide mfa-code in the login request. |
Invalid MFA code | Code expired or wrong device. | Ensure device clock is synced; check if using the correct account. |
Account locked | Too many failed attempts. | Wait for the lockout period to expire (default 15m). |
Unauthorized | Missing or invalid JWT token. | Provide a valid Authorization: Bearer <token> header. |
If your JWT tokens are being rejected:
exp claim hasn't passed.JWT_SECRET that was used to sign the token.HS256. Ensure your client isn't trying to use a different algorithm.Authorization: Bearer <token>.TOTP is highly sensitive to time. If your server or user's device clock is off by more than 30 seconds, codes will be rejected.
Last Updated: 2026-01-26
Version: 1.0.0
Status: Stable
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |