Skip to main content

Authentication Utilities

This document covers the utility functions for authentication and authorization in the BuildAppsWith platform. These utilities help with common auth-related tasks such as permission checking, token management, and auth state validation.

Core Auth Utilities

Role and Permission Utilities

hasRole

Checks if a user has a specific role.
import { hasRole } from '@/lib/auth/utils';
import { UserRole } from '@/lib/auth/types';

// Example usage
const userRoles = [UserRole.USER, UserRole.BUILDER];
const isAdmin = hasRole(userRoles, UserRole.ADMIN); // false
const isBuilder = hasRole(userRoles, UserRole.BUILDER); // true
Parameters
ParameterTypeDescription
rolesUserRole[]Array of user roles
roleUserRoleRole to check for
Returns
TypeDescription
booleanWhether the user has the role

hasPermission

Checks if a user has a specific permission based on their roles.
import { hasPermission } from '@/lib/auth/utils';
import { Permission } from '@/lib/auth/types';

// Example usage
const userRoles = [UserRole.USER, UserRole.BUILDER];
const canModerateContent = hasPermission(userRoles, Permission.MODERATE_CONTENT); // false
const canCreateProject = hasPermission(userRoles, Permission.CREATE_PROJECT); // true
Parameters
ParameterTypeDescription
rolesUserRole[]Array of user roles
permissionPermissionPermission to check for
Returns
TypeDescription
booleanWhether the user has the permission

getRolePermissions

Gets all permissions for a specific role.
import { getRolePermissions } from '@/lib/auth/utils';
import { UserRole } from '@/lib/auth/types';

// Example usage
const adminPermissions = getRolePermissions(UserRole.ADMIN);
// Returns array of all admin permissions
Parameters
ParameterTypeDescription
roleUserRoleRole to get permissions for
Returns
TypeDescription
Permission[]Array of permissions for the role

Token Utilities

parseAuthToken

Parses and validates a JWT auth token.
import { parseAuthToken } from '@/lib/auth/utils';

// Example usage
try {
  const tokenData = parseAuthToken(token);
  console.log('User ID:', tokenData.sub);
} catch (error) {
  console.error('Invalid token:', error.message);
}
Parameters
ParameterTypeDescription
tokenstringJWT token to parse
Returns
TypeDescription
TokenPayloadDecoded token payload

isTokenExpired

Checks if a token is expired.
import { isTokenExpired } from '@/lib/auth/utils';

// Example usage
const isExpired = isTokenExpired(token);
if (isExpired) {
  // Handle expired token
}
Parameters
ParameterTypeDescription
tokenstringJWT token to check
Returns
TypeDescription
booleanWhether the token is expired

Auth State Utilities

isAuthenticated

Checks if a user is authenticated based on auth state.
import { isAuthenticated } from '@/lib/auth/utils';

// Example usage
const authState = getAuthState();
if (isAuthenticated(authState)) {
  // User is authenticated
}
Parameters
ParameterTypeDescription
authStateAuthStateCurrent auth state
Returns
TypeDescription
booleanWhether the user is authenticated

isAuthLoading

Checks if auth state is currently loading.
import { isAuthLoading } from '@/lib/auth/utils';

// Example usage
const authState = getAuthState();
if (isAuthLoading(authState)) {
  // Show loading spinner
}
Parameters
ParameterTypeDescription
authStateAuthStateCurrent auth state
Returns
TypeDescription
booleanWhether auth state is loading

Error Handling Utilities

formatAuthError

Formats authentication errors into user-friendly messages.
import { formatAuthError } from '@/lib/auth/utils';

// Example usage
try {
  await signIn(email, password);
} catch (error) {
  const message = formatAuthError(error);
  showErrorMessage(message);
}
Parameters
ParameterTypeDescription
errorunknownError from auth operation
Returns
TypeDescription
stringUser-friendly error message

isAuthError

Type guard to check if an error is an authentication error.
import { isAuthError } from '@/lib/auth/utils';

// Example usage
try {
  await someOperation();
} catch (error) {
  if (isAuthError(error)) {
    // Handle auth error
    if (error.code === 'invalid_credentials') {
      // Handle specific auth error
    }
  } else {
    // Handle other errors
  }
}
Parameters
ParameterTypeDescription
errorunknownError to check
Returns
TypeDescription
booleanWhether the error is an auth error

Session Utilities

extractUserDataFromSession

Extracts standardized user data from a Clerk session.
import { extractUserDataFromSession } from '@/lib/auth/utils';

// Example usage
const session = await clerkClient.sessions.getSession(sessionId);
const userData = extractUserDataFromSession(session);
Parameters
ParameterTypeDescription
sessionSessionClerk session object
Returns
TypeDescription
UserDataStandardized user data

getRolesFromSession

Extracts user roles from a Clerk session.
import { getRolesFromSession } from '@/lib/auth/utils';

// Example usage
const session = await clerkClient.sessions.getSession(sessionId);
const roles = getRolesFromSession(session);
Parameters
ParameterTypeDescription
sessionSessionClerk session object
Returns
TypeDescription
UserRole[]Array of user roles

Implementation Examples

Role-Based Route Protection

import { hasRole } from '@/lib/auth/utils';
import { UserRole } from '@/lib/auth/types';

// Middleware to protect routes by role
export function roleMiddleware(requiredRole: UserRole) {
  return function(req, res, next) {
    const userRoles = req.user?.roles || [];
    
    if (!hasRole(userRoles, requiredRole)) {
      return res.status(403).json({
        error: 'Forbidden',
        message: 'You do not have permission to access this resource'
      });
    }
    
    next();
  };
}

// Usage in an API route
app.get('/admin/dashboard', 
  authMiddleware, // Verify authentication first
  roleMiddleware(UserRole.ADMIN), // Then check for admin role
  (req, res) => {
    // Only admins reach this point
    res.json({ data: 'Admin dashboard data' });
  }
);

Permission Checking

import { hasPermission } from '@/lib/auth/utils';
import { Permission } from '@/lib/auth/types';

// Function that requires specific permission
function moderateContent(user, contentId) {
  const userRoles = user.roles || [];
  
  if (!hasPermission(userRoles, Permission.MODERATE_CONTENT)) {
    throw new Error('Permission denied: Cannot moderate content');
  }
  
  // Proceed with content moderation
  return performModeration(contentId);
}

// Usage
try {
  const result = moderateContent(currentUser, 'content-123');
  console.log('Moderation successful:', result);
} catch (error) {
  console.error('Moderation failed:', error.message);
}

Token Validation

import { parseAuthToken, isTokenExpired } from '@/lib/auth/utils';

// Validate a token before using it
function validateAuthToken(token) {
  if (!token) {
    throw new Error('No token provided');
  }
  
  if (isTokenExpired(token)) {
    throw new Error('Token has expired');
  }
  
  try {
    const payload = parseAuthToken(token);
    return payload;
  } catch (error) {
    throw new Error(`Invalid token: ${error.message}`);
  }
}

// Usage
function authenticateRequest(req) {
  const token = req.headers.authorization?.split(' ')[1];
  
  try {
    const tokenData = validateAuthToken(token);
    req.user = {
      id: tokenData.sub,
      email: tokenData.email,
      roles: tokenData.roles
    };
    return true;
  } catch (error) {
    console.error('Authentication error:', error.message);
    return false;
  }
}

Best Practices

  1. Always use typed utility functions - Avoid manual role/permission checks
  2. Handle errors gracefully - Use error helpers to format user-friendly messages
  3. Validate auth state before using it - Check isAuthenticated/isAuthLoading
  4. Parse tokens safely - Always use try/catch with token utilities
  5. Keep utility functions pure - Don’t mix business logic with utility functions

See Also