Authentication
Staque IO uses JWT (JSON Web Token) based authentication with bcrypt password hashing for secure user management.
Authentication Flow
1. User submits credentials (username/email + password) ↓ 2. Server validates credentials against database ↓ 3. Password verified using bcrypt.compare() ↓ 4. JWT token generated with user info and 24h expiration ↓ 5. Token returned to client ↓ 6. Client stores token in localStorage ↓ 7. Token included in Authorization header for subsequent requests
Login API
POST /api/auth/login
Authenticates a user and returns a JWT token.
Request Body
{
"username": "john@example.com", // Email or username
"password": "securePassword123"
}Response (Success)
{
"success": true,
"message": "Login successful",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "uuid",
"username": "john",
"email": "john@example.com",
"name": "John Doe",
"organization": "Acme Corp",
"aws_region": "eu-north-1",
"role": "admin",
"is_active": true,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"last_login": "2024-01-10T12:00:00Z"
}
}Response (Error)
{
"success": false,
"message": "Invalid username or password"
}Token Validation
GET /api/auth/validate
Validates an existing JWT token and returns user information.
Request Headers
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Response
{
"success": true,
"message": "Token is valid",
"user": {
"id": "uuid",
"username": "john",
"email": "john@example.com",
"name": "John Doe",
"role": "admin",
...
}
}Logout
POST /api/auth/logout
Logs out the current user. The client should delete the stored token.
{
"success": true,
"message": "Logged out"
}JWT Token Structure
The JWT token contains the following payload:
{
"userId": "uuid",
"username": "john",
"role": "admin",
"iat": 1704067200, // Issued at timestamp
"exp": 1704153600 // Expiration timestamp (24 hours)
}User Roles
Staque IO supports three user roles with different permissions:
| Role | Permissions |
|---|---|
super_admin | Full system access, user management, credential viewing |
admin | Deploy resources, manage models, view credentials |
user | View deployments, chat with models, basic operations |
Protected Routes
Most API endpoints require authentication. Include the JWT token in the Authorization header:
fetch('/api/conversations', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
})Utility Functions
extractUserFromRequest()
Server-side utility to extract user information from JWT token:
import { extractUserFromRequest } from '@/utils/auth/jwt'
export async function GET(req: NextRequest) {
const userInfo = extractUserFromRequest(req)
if (!userInfo) {
return NextResponse.json(
{ success: false, error: 'Authentication required' },
{ status: 401 }
)
}
// Check role
if (userInfo.role !== 'admin' && userInfo.role !== 'super_admin') {
return NextResponse.json(
{ success: false, error: 'Admin privileges required' },
{ status: 403 }
)
}
// User is authenticated and authorized
// ...
}Password Security
Passwords are secured using bcrypt with the following features:
- Hashing: bcrypt with automatic salt generation
- Cost Factor: 10 rounds (configurable)
- Storage: Only password hash stored in database
- Verification: Constant-time comparison to prevent timing attacks
Password Hashing Example
import bcrypt from 'bcryptjs' // Hash password const password = 'userPassword123' const passwordHash = await bcrypt.hash(password, 10) // Verify password const isValid = await bcrypt.compare(password, passwordHash) // isValid === true
Client-Side Authentication
AuthContext
The application provides an AuthContext for managing authentication state:
import { useAuth } from '@/contexts/AuthContext'
function MyComponent() {
const { user, login, logout, isAuthenticated, isLoading } = useAuth()
if (isLoading) {
return <div>Loading...</div>
}
if (!isAuthenticated) {
return <div>Please log in</div>
}
return (
<div>
<h1>Welcome, {user.name}!</h1>
<button onClick={logout}>Logout</button>
</div>
)
}Security Best Practices
⚠️ Important Security Notes
- JWT Secret: Use a strong, randomly generated secret (minimum 256 bits)
- HTTPS Only: Always use HTTPS in production to prevent token interception
- Token Storage: Store tokens in localStorage or httpOnly cookies
- Token Rotation: Implement token refresh mechanism for long-lived sessions
- Logout: Clear tokens from storage on logout
- Rate Limiting: Implement rate limiting on login endpoints
- Password Policy: Enforce strong password requirements
Troubleshooting
401 Unauthorized
- Token is missing from request headers
- Token has expired (24 hour lifetime)
- Token signature is invalid
- User account has been deactivated
403 Forbidden
- User doesn't have required role/permissions
- Admin/super_admin privileges required for the endpoint
Common Issues
// ❌ Wrong: Missing Bearer prefix Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... // ✅ Correct: Include Bearer prefix Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...