Skip to content

Authentication

Authentication is the process of verifying who a user is, while authorization determines what they can access. This section covers various authentication methods, token management, and security best practices for HTTP servers.

Authentication Methods

Bearer Token Authentication

Bearer tokens are the most common authentication method for APIs, especially JWT (JSON Web Tokens).

Examples:

JWT Bearer Token Middleware:

JWT Bearer Token
import http
import json
import strings
import fmt

// JWT authentication middleware
function jwtAuthMiddleware(next function) {
    return function(request map, response map) {
        var authHeader = request["headers"]["Authorization"]

        if authHeader == None or authHeader == "" {
            sendUnauthorizedResponse(response, "Missing Authorization header")
            return
        }

        if !strings.HasPrefix(authHeader, "Bearer ") {
            sendUnauthorizedResponse(response, "Invalid Authorization header format")
            return
        }

        var token = strings.TrimPrefix(authHeader, "Bearer ")
        var claims = validateJWTToken(token)

        if claims == None {
            sendUnauthorizedResponse(response, "Invalid or expired token")
            return
        }

        // Add user information to request context
        request["user"] = claims["user"]
        request["userId"] = claims["sub"]
        request["roles"] = claims["roles"]
        request["authenticated"] = true

        next(request, response)
    }
}

// JWT token validation
function validateJWTToken(token string) {
    // In a real implementation, this would:
    // 1. Verify the token signature
    // 2. Check expiration
    // 3. Validate issuer and audience
    // 4. Return decoded claims

    // Simplified validation for example
    if token == "valid-jwt-token" {
        return {
            "sub": "user123",
            "user": {
                "id": 123,
                "username": "alice",
                "email": "alice@example.com"
            },
            "roles": ["user", "admin"],
            "exp": 1640995200,  // Expiration timestamp
            "iat": 1640908800   // Issued at timestamp
        }
    }

    return None
}

#### Mux-Level API Key Auth Helper

For simple header-based API key checks you can use the built-in helper
`http.WithAPIKeyAuth`, which attaches an authentication handler directly to a mux.

```harneet title="WithAPIKeyAuth on a Mux"
import http
import fmt

function protectedHandler(request any, response any) {
    response.json({"status": "ok", "path": request["path"]})
}

function startAPIKeyServer() {
    var server, serverErr = http.NewServer(":8080")
    if serverErr != None {
        fmt.Printf("Server error: %s\n", serverErr)
        return
    }

    var mux, muxErr = http.NewMux()
    if muxErr != None {
        fmt.Printf("Mux error: %s\n", muxErr)
        return
    }

    // Require a specific X-API-Key value for all HandleRoute routes on this mux
    var authMux, authErr = http.WithAPIKeyAuth(mux, "X-API-Key", "key_123abc")
    if authErr != None {
        fmt.Printf("WithAPIKeyAuth error: %s\n", authErr)
        return
    }

    var _, routeErr = http.HandleRoute(authMux, "GET", "/protected/{id}", protectedHandler)
    if routeErr != None {
        fmt.Printf("Route error: %s\n", routeErr)
        return
    }

    var setErr = http.SetHandler(server, authMux)[1]
    if setErr != None {
        fmt.Printf("SetHandler error: %s\n", setErr)
        return
    }

    fmt.Println("API key protected server starting on :8080")
    fmt.Println("Try: curl -H 'X-API-Key: key_123abc' http://localhost:8080/protected/1")
    http.ListenAndServe(server)
}

Mux-Level Auth and Rate Limit Hooks

In addition to middleware, you can attach hooks directly to a mux that run before each http.HandleRoute handler:

  • http.WithAuth(mux, authHandler) (mux, error)
  • http.WithRateLimit(mux, rateLimitHandler) (mux, error)
  • http.WithSimpleIPRateLimit(mux, requestsPerMinute) (mux, error)

These hooks are ideal for coarse-grained policies such as "all routes on this mux require authentication" or "limit each client IP to N requests per minute".

function sendUnauthorizedResponse(response map, message string) {
    var errorResponse = {
        "error": "Unauthorized",
        "message": message,
        "status": 401
    }

    var jsonData, _ = json.Marshal(errorResponse)
    http.WriteResponse(response, 401, "application/json", jsonData)
}

API Key Authentication

API keys are simple tokens used for service-to-service authentication.

Examples:

API Key Middleware:

API Key Auth
import http
import json
import fmt

// API key authentication middleware
function apiKeyAuthMiddleware(next function) {
    return function(request map, response map) {
        var apiKey = getAPIKeyFromRequest(request)

        if apiKey == "" {
            sendUnauthorizedResponse(response, "Missing API key")
            return
        }

        var keyInfo = validateAPIKey(apiKey)
        if keyInfo == None {
            sendUnauthorizedResponse(response, "Invalid API key")
            return
        }

        // Add API key information to request
        request["apiKey"] = apiKey
        request["apiKeyInfo"] = keyInfo
        request["authenticated"] = true

        next(request, response)
    }
}

function getAPIKeyFromRequest(request map) {
    var headers = request["headers"]
    var query = request["query"]

    // Check X-API-Key header
    var headerKey = headers["X-API-Key"]
    if headerKey != None and headerKey != "" {
        return headerKey
    }

    // Check Authorization header with API key format
    var authHeader = headers["Authorization"]
    if authHeader != None and strings.HasPrefix(authHeader, "ApiKey ") {
        return strings.TrimPrefix(authHeader, "ApiKey ")
    }

    // Check query parameter
    var queryKey = query["api_key"]
    if queryKey != None and queryKey != "" {
        return queryKey
    }

    return ""
}

function validateAPIKey(apiKey string) {
    // In a real implementation, this would check against a database
    var validKeys = {
        "key_123abc": {
            "id": "key_123abc",
            "name": "Production API Key",
            "userId": 123,
            "permissions": ["read", "write"],
            "rateLimit": 1000,
            "active": true
        },
        "key_456def": {
            "id": "key_456def", 
            "name": "Development API Key",
            "userId": 456,
            "permissions": ["read"],
            "rateLimit": 100,
            "active": true
        }
    }

    var keyInfo = validKeys[apiKey]
    if keyInfo != None and keyInfo["active"] {
        return keyInfo
    }

    return None
}

Basic Authentication

HTTP Basic Authentication sends credentials in the Authorization header.

Examples:

Basic Auth Middleware:

Basic Auth
import http
import json
import strings
import fmt

// Basic authentication middleware
function basicAuthMiddleware(next function) {
    return function(request map, response map) {
        var authHeader = request["headers"]["Authorization"]

        if authHeader == None or !strings.HasPrefix(authHeader, "Basic ") {
            sendBasicAuthChallenge(response)
            return
        }

        var credentials = strings.TrimPrefix(authHeader, "Basic ")
        var decodedCreds = base64Decode(credentials)  // Simplified base64 decode
        var parts = strings.Split(decodedCreds, ":")

        if len(parts) != 2 {
            sendBasicAuthChallenge(response)
            return
        }

        var username = parts[0]
        var password = parts[1]

        var user = authenticateUser(username, password)
        if user == None {
            sendBasicAuthChallenge(response)
            return
        }

        // Add user to request context
        request["user"] = user
        request["authenticated"] = true

        next(request, response)
    }
}

function sendBasicAuthChallenge(response map) {
    http.SetResponseHeader(response, "WWW-Authenticate", "Basic realm=\"API\"")

    var errorResponse = {
        "error": "Unauthorized",
        "message": "Basic authentication required",
        "status": 401
    }

    var jsonData, _ = json.Marshal(errorResponse)
    http.WriteResponse(response, 401, "application/json", jsonData)
}

function authenticateUser(username string, password string) {
    // In a real implementation, this would check against a database
    // with properly hashed passwords
    var users = {
        "admin": {
            "username": "admin",
            "passwordHash": "hashed_password_123",  // In reality, use bcrypt
            "roles": ["admin", "user"],
            "active": true
        },
        "user": {
            "username": "user", 
            "passwordHash": "hashed_password_456",
            "roles": ["user"],
            "active": true
        }
    }

    var user = users[username]
    if user != None and user["active"] and verifyPassword(password, user["passwordHash"]) {
        return user
    }

    return None
}

function verifyPassword(password string, hash string) {
    // In a real implementation, use proper password hashing (bcrypt, scrypt, etc.)
    return password == "password123"  // Simplified for example
}

Session-Based Authentication

Session-based authentication uses server-side sessions with cookies.

Examples:

Session Authentication:

Session Auth
import http
import json
import fmt

// Session-based authentication middleware
function sessionAuthMiddleware(next function) {
    return function(request map, response map) {
        var sessionId = getSessionIdFromRequest(request)

        if sessionId == "" {
            sendUnauthorizedResponse(response, "No session found")
            return
        }

        var session = getSession(sessionId)
        if session == None or isSessionExpired(session) {
            sendUnauthorizedResponse(response, "Invalid or expired session")
            return
        }

        // Update session last accessed time
        updateSessionAccess(sessionId)

        // Add session and user to request context
        request["session"] = session
        request["user"] = session["user"]
        request["authenticated"] = true

        next(request, response)
    }
}

function getSessionIdFromRequest(request map) {
    var cookies = request["cookies"]
    if cookies != None {
        var sessionId = cookies["session_id"]
        if sessionId != None {
            return sessionId
        }
    }

    // Fallback to header
    var sessionHeader = request["headers"]["X-Session-ID"]
    if sessionHeader != None {
        return sessionHeader
    }

    return ""
}

// Session management functions
var sessions = {}  // In-memory session store (use Redis/database in production)

function createSession(user map) {
    var sessionId = generateSessionId()
    var session = {
        "id": sessionId,
        "user": user,
        "createdAt": getCurrentTimestamp(),
        "lastAccessed": getCurrentTimestamp(),
        "expiresAt": getCurrentTimestamp() + 3600  // 1 hour
    }

    sessions[sessionId] = session
    return session
}

function getSession(sessionId string) {
    return sessions[sessionId]
}

function updateSessionAccess(sessionId string) {
    var session = sessions[sessionId]
    if session != None {
        session["lastAccessed"] = getCurrentTimestamp()
        // Extend expiration
        session["expiresAt"] = getCurrentTimestamp() + 3600
    }
}

function isSessionExpired(session map) {
    var expiresAt = session["expiresAt"]
    var currentTime = getCurrentTimestamp()
    return currentTime > expiresAt
}

function destroySession(sessionId string) {
    delete(sessions, sessionId)
}

function generateRandomString() string {
    return "abcde"
}

function generateSessionId() {
    // In a real implementation, use a cryptographically secure random generator
    return "session_" + generateRandomString(32)
}

Authorization and Role-Based Access Control

Authorization determines what authenticated users can access.

Examples:

Role-Based Authorization:

Role-Based Authorization
import http
import json
import fmt

// Role-based authorization middleware
function requireRole(requiredRole string) {
    return function(next function) {
        return function(request map, response map) {
            var user = request["user"]
            if user == None {
                sendForbiddenResponse(response, "Authentication required")
                return
            }

            var userRoles = user["roles"]
            if userRoles == None {
                sendForbiddenResponse(response, "No roles assigned")
                return
            }

            var hasRole = false
            for role in userRoles {
                if role == requiredRole {
                    hasRole = true
                    break
                }
            }

            if !hasRole {
                sendForbiddenResponse(response, "Insufficient permissions")
                return
            }

            next(request, response)
        }
    }
}

// Permission-based authorization
function requirePermission(requiredPermission string) {
    return function(next function) {
        return function(request map, response map) {
            var user = request["user"]
            if user == None {
                sendForbiddenResponse(response, "Authentication required")
                return
            }

            var hasPermission = checkUserPermission(user, requiredPermission)
            if !hasPermission {
                sendForbiddenResponse(response, "Permission denied")
                return
            }

            next(request, response)
        }
    }
}

function checkUserPermission(user map, permission string) {
    var userRoles = user["roles"]
    if userRoles == None {
        return false
    }

    // Check role-based permissions
    var rolePermissions = {
        "admin": ["read", "write", "delete", "manage_users"],
        "editor": ["read", "write"],
        "user": ["read"]
    }

    for role in userRoles {
        var permissions = rolePermissions[role]
        if permissions != None {
            for perm in permissions {
                if perm == permission {
                    return true
                }
            }
        }
    }

    return false
}

function sendForbiddenResponse(response map, message string) {
    var errorResponse = {
        "error": "Forbidden",
        "message": message,
        "status": 403
    }

    var jsonData, _ = json.Marshal(errorResponse)
    http.WriteResponse(response, 403, "application/json", jsonData)
}

// Usage examples
function setupProtectedRoutes() {
    var mux = http.NewMux()[0]

    // Public routes
    http.HandleFunc(mux, "/", homeHandler)
    http.HandleFunc(mux, "/login", loginHandler)

    // Protected routes with different authorization levels
    var userHandler = chainMiddleware([jwtAuthMiddleware, requireRole("user")])(userProfileHandler)
    var adminHandler = chainMiddleware([jwtAuthMiddleware, requireRole("admin")])(adminDashboardHandler)
    var editorHandler = chainMiddleware([jwtAuthMiddleware, requirePermission("write")])(editContentHandler)

    http.HandleFunc(mux, "/profile", userHandler)
    http.HandleFunc(mux, "/admin", adminHandler)
    http.HandleFunc(mux, "/edit", editorHandler)

    return mux
}

Token Management

JWT Token Generation and Validation

JWT Token Management
import http
import json
import fmt

// JWT token generation (simplified)
function generateJWTToken(user map) {
    var header = {
        "alg": "HS256",
        "typ": "JWT"
    }

    var payload = {
        "sub": user["id"],
        "username": user["username"],
        "email": user["email"],
        "roles": user["roles"],
        "iat": getCurrentTimestamp(),
        "exp": getCurrentTimestamp() + 3600  // 1 hour expiration
    }

    // In a real implementation, properly encode and sign the JWT
    var headerEncoded = base64Encode(json.Marshal(header)[0])
    var payloadEncoded = base64Encode(json.Marshal(payload)[0])
    var signature = signJWT(headerEncoded + "." + payloadEncoded, "secret-key")

    return headerEncoded + "." + payloadEncoded + "." + signature
}

// Token refresh endpoint
function tokenRefreshHandler(request map, response map) {
    var refreshToken = getRefreshTokenFromRequest(request)

    if refreshToken == "" {
        sendUnauthorizedResponse(response, "Missing refresh token")
        return
    }

    var tokenInfo = validateRefreshToken(refreshToken)
    if tokenInfo == None {
        sendUnauthorizedResponse(response, "Invalid refresh token")
        return
    }

    var user = getUserById(tokenInfo["userId"])
    if user == None {
        sendUnauthorizedResponse(response, "User not found")
        return
    }

    // Generate new access token
    var newAccessToken = generateJWTToken(user)
    var newRefreshToken = generateRefreshToken(user["id"])

    // Invalidate old refresh token
    invalidateRefreshToken(refreshToken)

    var tokenResponse = {
        "access_token": newAccessToken,
        "refresh_token": newRefreshToken,
        "token_type": "Bearer",
        "expires_in": 3600
    }

    var jsonData, _ = json.Marshal(tokenResponse)
    http.WriteResponse(response, 200, "application/json", jsonData)
}

function generateRefreshToken(userId string) {
    var refreshToken = "refresh_" + generateRandomString(64)

    // Store refresh token (in database in real implementation)
    var tokenInfo = {
        "token": refreshToken,
        "userId": userId,
        "createdAt": getCurrentTimestamp(),
        "expiresAt": getCurrentTimestamp() + 604800  // 7 days
    }

    storeRefreshToken(refreshToken, tokenInfo)
    return refreshToken
}

Login and Logout Endpoints

Login Handler

Login Handler
import http
import json
import fmt

// Login endpoint
function loginHandler(request map, response map) {
    var method = request["method"]

    if method != "POST" {
        http.WriteResponse(response, 405, "application/json", "{\"error\": \"Method not allowed\"}")
        return
    }

    var body = request["body"]
    var loginData, parseErr = json.Unmarshal(body)

    if parseErr != None {
        http.WriteResponse(response, 400, "application/json", "{\"error\": \"Invalid JSON\"}")
        return
    }

    var username = loginData["username"]
    var password = loginData["password"]

    if username == None or password == None {
        http.WriteResponse(response, 400, "application/json", "{\"error\": \"Username and password required\"}")
        return
    }

    // Authenticate user
    var user = authenticateUser(username, password)
    if user == None {
        // Add delay to prevent timing attacks
        sleep(1000)  // 1 second delay
        http.WriteResponse(response, 401, "application/json", "{\"error\": \"Invalid credentials\"}")
        return
    }

    // Generate tokens
    var accessToken = generateJWTToken(user)
    var refreshToken = generateRefreshToken(user["id"])

    // Create session (if using session-based auth)
    var session = createSession(user)

    // Set session cookie
    http.SetCookie(response, "session_id", session["id"], {
        "httpOnly": true,
        "secure": true,
        "sameSite": "strict",
        "maxAge": 3600
    })

    var loginResponse = {
        "success": true,
        "user": {
            "id": user["id"],
            "username": user["username"],
            "email": user["email"],
            "roles": user["roles"]
        },
        "tokens": {
            "access_token": accessToken,
            "refresh_token": refreshToken,
            "token_type": "Bearer",
            "expires_in": 3600
        }
    }

    var jsonData, _ = json.Marshal(loginResponse)
    http.WriteResponse(response, 200, "application/json", jsonData)
}

// Logout endpoint
function logoutHandler(request map, response map) {
    var method = request["method"]

    if method != "POST" {
        http.WriteResponse(response, 405, "application/json", "{\"error\": \"Method not allowed\"}")
        return
    }

    // Get session ID from cookie
    var sessionId = getSessionIdFromRequest(request)
    if sessionId != "" {
        destroySession(sessionId)
    }

    // Get refresh token and invalidate it
    var body = request["body"]
    if body != "" {
        var logoutData, parseErr = json.Unmarshal(body)
        if parseErr == None {
            var refreshToken = logoutData["refresh_token"]
            if refreshToken != None {
                invalidateRefreshToken(refreshToken)
            }
        }
    }

    // Clear session cookie
    http.SetCookie(response, "session_id", "", {
        "httpOnly": true,
        "secure": true,
        "sameSite": "strict",
        "maxAge": -1  // Expire immediately
    })

    var logoutResponse = {
        "success": true,
        "message": "Logged out successfully"
    }

    var jsonData, _ = json.Marshal(logoutResponse)
    http.WriteResponse(response, 200, "application/json", jsonData)
}

Security Best Practices

Password Security

Password Security
import http
import json

// Secure password hashing (conceptual - use proper crypto library)
function hashPassword(password string) {
    // In a real implementation, use bcrypt, scrypt, or Argon2
    return bcryptHash(password, 12)  // Cost factor 12
}

function verifyPassword(password string, hash string) {
    return bcryptVerify(password, hash)
}

// Password strength validation
function validatePasswordStrength(password string) {
    var errors = []

    if len(password) < 8 {
        errors = append(errors, "Password must be at least 8 characters long")
    }

    if !containsUppercase(password) {
        errors = append(errors, "Password must contain at least one uppercase letter")
    }

    if !containsLowercase(password) {
        errors = append(errors, "Password must contain at least one lowercase letter")
    }

    if !containsDigit(password) {
        errors = append(errors, "Password must contain at least one digit")
    }

    if !containsSpecialChar(password) {
        errors = append(errors, "Password must contain at least one special character")
    }

    return errors
}

Rate Limiting for Authentication

Auth Rate Limiting
import http
import fmt

// Authentication rate limiting
function authRateLimitMiddleware(maxAttempts int, windowMinutes int) {
    var attempts = {}  // Track failed attempts by IP

    return function(next function) {
        return function(request map, response map) {
            var clientIP = getClientIP(request)
            var currentTime = getCurrentMinute()
            var key = clientIP + ":" + currentTime

            var attemptCount = attempts[key]
            if attemptCount == None {
                attemptCount = 0
            }

            if attemptCount >= maxAttempts {
                var errorResponse = {
                    "error": "Too Many Attempts",
                    "message": "Too many authentication attempts. Please try again later.",
                    "retryAfter": windowMinutes * 60
                }

                http.SetResponseHeader(response, "Retry-After", windowMinutes * 60)
                var jsonData, _ = json.Marshal(errorResponse)
                http.WriteResponse(response, 429, "application/json", jsonData)
                return
            }

            // Track this attempt
            attempts[key] = attemptCount + 1

            next(request, response)
        }
    }
}

CSRF Protection

CSRF Protection
import http
import json

// CSRF protection middleware
function csrfProtectionMiddleware(next function) {
    return function(request map, response map) {
        var method = request["method"]

        // Only check CSRF for state-changing methods
        if method == "POST" or method == "PUT" or method == "DELETE" or method == "PATCH" {
            var csrfToken = getCSRFTokenFromRequest(request)
            var sessionToken = getCSRFTokenFromSession(request)

            if csrfToken == "" or sessionToken == "" or csrfToken != sessionToken {
                var errorResponse = {
                    "error": "CSRF Token Mismatch",
                    "message": "Invalid or missing CSRF token"
                }

                var jsonData, _ = json.Marshal(errorResponse)
                http.WriteResponse(response, 403, "application/json", jsonData)
                return
            }
        }

        next(request, response)
    }
}

function getCSRFTokenFromRequest(request map) {
    var headers = request["headers"]

    // Check X-CSRF-Token header
    var headerToken = headers["X-CSRF-Token"]
    if headerToken != None {
        return headerToken
    }

    // Check form data (if parsing form data)
    var formData = request["formData"]
    if formData != None {
        var formToken = formData["csrf_token"]
        if formToken != None {
            return formToken
        }
    }

    return ""
}

Complete Authentication Example

Complete Auth System
import http
import json
import fmt

// Complete authentication setup
function setupAuthenticatedServer() {
    var mux = http.NewMux()[0]

    // Public routes
    http.HandleFunc(mux, "/", homeHandler)
    http.HandleFunc(mux, "/login", loginHandler)
    http.HandleFunc(mux, "/register", registerHandler)

    // Token management
    http.HandleFunc(mux, "/refresh", tokenRefreshHandler)

    // Protected routes
    var protectedMux = http.NewMux()[0]

    // User routes (requires authentication)
    var userRoutes = chainMiddleware([jwtAuthMiddleware])(userHandler)
    http.HandleFunc(protectedMux, "/profile", userRoutes)
    http.HandleFunc(protectedMux, "/logout", logoutHandler)

    // Admin routes (requires admin role)
    var adminRoutes = chainMiddleware([jwtAuthMiddleware, requireRole("admin")])(adminHandler)
    http.HandleFunc(protectedMux, "/admin", adminRoutes)

    // API routes with rate limiting
    var apiRoutes = chainMiddleware([
        authRateLimitMiddleware(10, 1),  // 10 attempts per minute
        apiKeyAuthMiddleware
    ])(apiHandler)
    http.HandleFunc(protectedMux, "/api/", apiRoutes)

    // Mount protected routes
    http.Handle(mux, "/protected/", http.StripPrefix("/protected", protectedMux))

    return mux
}

// Start authenticated server
function startAuthServer() {
    var mux = setupAuthenticatedServer()
    var server = http.NewServer(":8080")[0]

    // Add security middleware
    var secureHandler = chainMiddleware([
        loggingMiddleware,
        corsMiddleware,
        securityHeadersMiddleware,
        csrfProtectionMiddleware
    ])(mux)

    http.SetHandler(server, secureHandler)

    fmt.Println("🔐 Authenticated server starting on :8080")
    http.ListenAndServe(server)
}

Next Steps