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:

RolePermissions
super_adminFull system access, user management, credential viewing
adminDeploy resources, manage models, view credentials
userView 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...