Authentication
Trokky uses JWT-based authentication with role-based access control (RBAC) to secure your content API.
Overview
Section titled “Overview”The authentication system provides:
- JWT token-based authentication
- Role-based access control
- Secure password hashing
- Session management
- Multi-environment crypto support
Quick Setup
Section titled “Quick Setup”Basic Configuration
Section titled “Basic Configuration”const trokky = await TrokkyExpress.create({ security: { adminUser: { username: 'admin', password: 'secure-password', }, jwtSecret: process.env.JWT_SECRET || 'development-secret', tokenExpiry: '7d', }, // ...});Environment Variables
Section titled “Environment Variables”For production, use environment variables:
TROKKY_ADMIN_USERNAME=adminTROKKY_ADMIN_PASSWORD=your-secure-passwordTROKKY_JWT_SECRET=your-random-secret-keyconst trokky = await TrokkyExpress.create({ security: { adminUser: { username: process.env.TROKKY_ADMIN_USERNAME, password: process.env.TROKKY_ADMIN_PASSWORD, }, jwtSecret: process.env.TROKKY_JWT_SECRET, }, // ...});User Roles
Section titled “User Roles”Trokky includes four built-in roles:
| Role | Description | Permissions |
|---|---|---|
admin | Full system access | All operations |
editor | Content management | CRUD on all content |
writer | Limited content management | Create/update own content |
viewer | Read-only access | Read content only |
Role Permissions Matrix
Section titled “Role Permissions Matrix”| Action | Admin | Editor | Writer | Viewer |
|---|---|---|---|---|
| Read documents | Yes | Yes | Yes | Yes |
| Create documents | Yes | Yes | Yes | No |
| Update any document | Yes | Yes | No | No |
| Update own documents | Yes | Yes | Yes | No |
| Delete documents | Yes | Yes | No | No |
| Manage users | Yes | No | No | No |
| Access settings | Yes | No | No | No |
| Upload media | Yes | Yes | Yes | No |
| Delete media | Yes | Yes | No | No |
User Management
Section titled “User Management”Creating Users Programmatically
Section titled “Creating Users Programmatically”import { TrokkyCore } from '@trokky/core';
// After initializationconst user = await trokky.core.users.create({ username: 'editor@example.com', password: 'user-password', role: 'editor', name: 'John Editor',});User Storage
Section titled “User Storage”By default, users are stored alongside content using the configured storage adapter:
content/└── _users/ ├── admin.json └── editor@example.com.jsonUser Document Structure
Section titled “User Document Structure”{ "_id": "user-abc123", "username": "editor@example.com", "passwordHash": "$2b$10$...", "role": "editor", "name": "John Editor", "createdAt": "2024-01-15T10:00:00Z", "lastLogin": "2024-01-20T14:30:00Z"}Authentication Flow
Section titled “Authentication Flow”POST /api/auth/loginContent-Type: application/json
{ "username": "admin", "password": "your-password"}Response:
{ "token": "eyJhbGciOiJIUzI1NiIs...", "user": { "id": "user-abc123", "username": "admin", "role": "admin", "name": "Administrator" }, "expiresAt": "2024-01-22T10:00:00Z"}Using the Token
Section titled “Using the Token”Include the token in subsequent requests:
GET /api/documents/postAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...Refresh Token
Section titled “Refresh Token”POST /api/auth/refreshAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...Logout
Section titled “Logout”POST /api/auth/logoutAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...Security Configuration
Section titled “Security Configuration”Full Configuration Options
Section titled “Full Configuration Options”const trokky = await TrokkyExpress.create({ security: { // Admin user (created on first startup) adminUser: { username: 'admin', password: 'secure-password', email: 'admin@example.com', },
// JWT settings jwtSecret: process.env.JWT_SECRET, tokenExpiry: '7d', // Token lifetime refreshTokenExpiry: '30d', // Refresh token lifetime
// Password requirements passwordPolicy: { minLength: 8, requireUppercase: true, requireLowercase: true, requireNumbers: true, requireSpecial: false, },
// Rate limiting rateLimit: { login: { windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // 5 attempts }, },
// Session settings session: { maxConcurrent: 5, // Max sessions per user revokeOnPasswordChange: true, }, }, // ...});Protecting Routes
Section titled “Protecting Routes”Public vs Protected Endpoints
Section titled “Public vs Protected Endpoints”By default:
GET /api/documents/*- Public (read access)POST/PUT/DELETE /api/documents/*- Protected (requires authentication)GET /api/media/*- PublicPOST /api/media/*- Protected/api/auth/*- Public (login/logout)/api/users/*- Admin only
Custom Route Protection
Section titled “Custom Route Protection”// In your Express appimport { requireAuth, requireRole } from '@trokky/express';
// Require any authenticated userapp.get('/api/custom', requireAuth(), (req, res) => { res.json({ user: req.user });});
// Require specific roleapp.post('/api/admin-only', requireRole('admin'), (req, res) => { res.json({ message: 'Admin access granted' });});
// Require one of multiple rolesapp.put('/api/editors', requireRole(['admin', 'editor']), (req, res) => { res.json({ message: 'Editor access granted' });});Custom Authentication
Section titled “Custom Authentication”External Identity Providers
Section titled “External Identity Providers”Integrate with OAuth providers:
const trokky = await TrokkyExpress.create({ security: { // ... other options
oauth: { providers: [ { name: 'google', clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackUrl: '/api/auth/google/callback', }, ], }, }, // ...});Custom User Validation
Section titled “Custom User Validation”const trokky = await TrokkyExpress.create({ security: { // Custom validation before user creation validateUser: async (userData) => { // Check against external system const isAllowed = await checkExternalAuth(userData.email); if (!isAllowed) { throw new Error('User not authorized'); } return true; },
// Custom role assignment assignRole: async (userData) => { // Assign role based on email domain if (userData.email.endsWith('@admin.example.com')) { return 'admin'; } return 'editor'; }, }, // ...});Security Best Practices
Section titled “Security Best Practices”JWT Secret
Section titled “JWT Secret”Generate a strong secret for production:
# Generate a secure random secretopenssl rand -base64 64Password Storage
Section titled “Password Storage”Trokky uses bcrypt for password hashing with configurable cost factor:
security: { bcryptRounds: 12, // Higher = more secure but slower}Always use HTTPS in production:
// Force HTTPS redirectapp.use((req, res, next) => { if (req.headers['x-forwarded-proto'] !== 'https') { return res.redirect(`https://${req.headers.host}${req.url}`); } next();});Cookie Settings
Section titled “Cookie Settings”For cookie-based sessions:
security: { cookie: { secure: true, // HTTPS only httpOnly: true, // No JavaScript access sameSite: 'strict', // CSRF protection maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days },}Audit Logging
Section titled “Audit Logging”Track authentication events:
const trokky = await TrokkyExpress.create({ security: { auditLog: { enabled: true, events: ['login', 'logout', 'loginFailed', 'passwordChange', 'userCreate'], }, }, // ...});
// Access audit logsconst logs = await trokky.core.audit.getEvents({ type: 'loginFailed', since: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours});Next Steps
Section titled “Next Steps”- Media Handling - Configure media uploads and processing
- Studio Customization - Customize the admin interface
- Deployment - Deploy securely to production