Hooks

The NextJS SDK provides several React hooks to help you integrate Heimdall authentication and authorization into your application.

Available Hooks

useAuth

The useAuth hook provides access to authentication state and methods.

const { user, isAuthenticated, login, logout } = useAuth()

Properties

  • user: The current authenticated user object (see User model)
  • isAuthenticated: Boolean indicating if the user is authenticated
  • login: Function to initiate the login flow
  • logout: Function to log out the current user

useUser

The useUser hook provides access to the current user's information and profile management.

const { user, updateProfile, isLoading } = useUser()

Properties

  • user: The current user's profile information (see User model)
  • updateProfile: Function to update user profile information
  • isLoading: Boolean indicating if user data is being loaded

useSession

The useSession hook provides access to the current session information.

const { session, refreshSession } = useSession()

Properties

  • session: The current session object (see Session model)
  • refreshSession: Function to refresh the current session

useOrganization

The useOrganization hook provides access to organization-related functionality and data.

const {
  organizations,
  currentOrganization,
  isLoading,
  listOrganizations,
  getOrganization,
  createOrganization,
  updateOrganization,
  deleteOrganization,
} = useOrganization()

Properties

  • organizations: Array of organizations accessible to the current user (see Organization model)
  • currentOrganization: The currently selected organization (see Organization model)
  • isLoading: Boolean indicating if organization data is being loaded

Methods

  • listOrganizations(): Fetches all organizations accessible to the current user
  • getOrganization(organizationId: string): Fetches details for a specific organization
  • createOrganization(data: CreateOrganizationData): Creates a new organization
  • updateOrganization(organizationId: string, data: UpdateOrganizationData): Updates an organization's details
  • deleteOrganization(organizationId: string): Soft deletes an organization

Types

interface CreateOrganizationData {
  name: string
}

interface UpdateOrganizationData {
  name?: string
}

useTeam

The useTeam hook provides comprehensive team management functionality within an organization.

const {
  teams,
  currentTeam,
  isLoading,
  listTeams,
  createTeam,
  deleteTeam,
  leaveTeam,
  inviteUser,
  removeUser,
  cancelInvite,
} = useTeam()

Properties

  • teams: Array of teams in the current organization (see Team model)
  • currentTeam: The currently selected team (see Team model)
  • isLoading: Boolean indicating if team data is being loaded

Methods

  • listTeams(): Fetches all teams in the current organization
  • createTeam(teamData): Creates a new team in the organization
  • deleteTeam(teamId): Deletes a team from the organization
  • leaveTeam(teamId): Removes the current user from a team
  • inviteUser(teamId, email, role): Sends an invitation to join a team
  • removeUser(teamId, userId): Removes a user from a team
  • cancelInvite(teamId, inviteId): Cancels a pending team invitation

useUserPermissions

The useUserPermissions hook provides access to permission-related functionality and checks.

const {
  permissions,
  userPermissions,
  isLoading,
  listPermissions,
  listUserPermissions,
  hasPermission,
} = useUserPermissions()

Properties

  • permissions: Array of all available permissions (see Permission model)
  • userPermissions: Array of permissions granted to the current user (see UserPermission model)
  • isLoading: Boolean indicating if permission data is being loaded

Methods

  • listPermissions(): Fetches all available permissions in the system
  • listUserPermissions(userId?: string): Fetches permissions for a specific user (defaults to current user)
  • hasPermission(permission: string, context?: PermissionContext): Checks if the current user has a specific permission in the given context

useRoles

The useRoles hook provides access to role management functionality.

const {
  roles,
  userRoles,
  isLoading,
  listRoles,
  listUserRoles,
  addUserToRole, // Planned for future implementation
} = useRoles()

Properties

  • roles: Array of all available roles in the system
  • userRoles: Array of roles assigned to the current user
  • isLoading: Boolean indicating if role data is being loaded

Methods

  • listRoles(): Fetches all available roles in the system
  • listUserRoles(userId?: string): Fetches roles for a specific user (defaults to current user)
  • addUserToRole(userId: string, roleId: string, context?: RoleContext): Adds a user to a role or updates their existing role (planned for future implementation)

Types

interface Role {
  id: string
  name: string
  description: string
  permissions: string[]
  createdAt: string
  updatedAt: string
}

interface RoleContext {
  organizationId?: string
  teamId?: string
}

interface UserRole {
  id: string
  userId: string
  roleId: string
  context?: RoleContext
  assignedAt: string
  assignedBy: string
}

useOrganizationSettings

The useOrganizationSettings hook provides access to organization-specific settings management.

const {
  settings,
  isLoading,
  getSettings,
  getSetting,
  setSetting,
} = useOrganizationSettings(organizationId: string)

Properties

  • settings: Current organization settings (see OrganizationSettings model)
  • isLoading: Boolean indicating if settings data is being loaded

Methods

  • getSettings(): Fetches all settings for the organization
  • getSetting(key: string): Fetches a specific setting value
  • setSetting(key: string, value: SettingValue): Updates a specific setting value

Types

type SettingValue = string | number | boolean | string[] | null

interface OrganizationSetting {
  key: string
  value: SettingValue
  updatedAt: string
  updatedBy: string
}

useUserSettings

The useUserSettings hook provides access to user-specific settings management.

const {
  settings,
  isLoading,
  getSettings,
  getSetting,
  setSetting,
} = useUserSettings(userId?: string) // defaults to current user

Properties

  • settings: Current user settings
  • isLoading: Boolean indicating if settings data is being loaded

Methods

  • getSettings(): Fetches all settings for the user
  • getSetting(key: string): Fetches a specific setting value
  • setSetting(key: string, value: SettingValue): Updates a specific setting value

Types

type SettingValue = string | number | boolean | string[] | null

interface UserSetting {
  key: string
  value: SettingValue
  updatedAt: string
}

// Common user settings
interface UserPreferences {
  theme: 'light' | 'dark' | 'system'
  language: string
  notifications: {
    email: boolean
    push: boolean
  }
  displayName?: string
  timezone?: string
  dateFormat?: string
  timeFormat?: '12h' | '24h'
}

useFeatures

The useFeatures hook provides access to feature flags and feature management functionality. It allows you to check if features are enabled and manage feature flags in your application.

const { features, isLoading, isEnabled, getFeature } = useFeatures()

Properties

PropertyTypeDescription
featuresFeature[]List of all available features
isLoadingbooleanWhether the features are currently loading

Methods

MethodParametersReturn TypeDescription
isEnabledfeatureKey: stringbooleanCheck if a specific feature is enabled
getFeaturefeatureKey: stringFeature | undefinedGet detailed information about a specific feature

Type Definitions

interface Feature {
  key: string
  name: string
  description: string
  enabled: boolean
  type: 'boolean' | 'string' | 'number' | 'json'
  value: any
  metadata?: {
    [key: string]: any
  }
  createdAt: string
  updatedAt: string
}

Usage Example

import { useFeatures } from '@heimdall/nextjs'

export default function MyComponent() {
  const { features, isLoading, isEnabled, getFeature } = useFeatures()

  if (isLoading) {
    return <div>Loading features...</div>
  }

  // Check if a feature is enabled
  const isNewUIEnabled = isEnabled('new-ui')

  // Get detailed feature information
  const betaFeature = getFeature('beta-feature')

  return (
    <div>
      {isNewUIEnabled && <NewUIComponent />}

      {betaFeature?.enabled && (
        <div>
          <h2>{betaFeature.name}</h2>
          <p>{betaFeature.description}</p>
          {betaFeature.metadata?.betaUsers?.includes(userId) && (
            <BetaFeatureComponent />
          )}
        </div>
      )}
    </div>
  )
}

Feature Flag Types

The hook supports different types of feature flags:

  1. Boolean Flags: Simple on/off toggles

    const isEnabled = isEnabled('new-feature')
    
  2. String Flags: For configuration values

    const theme = getFeature('theme')?.value
    
  3. Number Flags: For numeric configurations

    const maxItems = getFeature('max-items')?.value
    
  4. JSON Flags: For complex configurations

    const config = getFeature('advanced-config')?.value
    

Best Practices

  1. Default Values: Always provide fallbacks for when features are not enabled

    const isEnabled = isEnabled('new-feature') ?? false
    
  2. Type Safety: Use TypeScript to ensure type safety with feature values

    const maxItems = (getFeature('max-items')?.value as number) ?? 10
    
  3. Loading States: Handle loading states appropriately

    if (isLoading) {
      return <LoadingSpinner />
    }
    
  4. Feature Groups: Use feature keys with namespaces for better organization

    const isEnabled = isEnabled('beta.new-ui')
    const isEnabled = isEnabled('experimental.analytics')
    

Future Considerations

The feature flagging system is designed to be extensible for future enhancements:

  1. A/B Testing: Support for A/B testing configurations
  2. User Targeting: Feature flags based on user properties
  3. Time-based Flags: Scheduled feature releases
  4. Percentage Rollouts: Gradual feature rollouts
  5. Environment-specific Flags: Different configurations per environment
  6. Audit Logging: Track feature flag changes
  7. Remote Configuration: Update feature flags without deployment

For more detailed information about feature flagging and its implementation, see the Feature Flagging documentation.

useImpersonation

The useImpersonation hook provides functionality to impersonate other users in the system. This is particularly useful for support and debugging scenarios where you need to view the application from another user's perspective.

const { isImpersonating, impersonatedUser, impersonate, stopImpersonating } =
  useImpersonation()

Properties

PropertyTypeDescription
isImpersonatingbooleanWhether a user is currently being impersonated
impersonatedUserUser | nullThe user being impersonated, if any

Methods

MethodParametersReturn TypeDescription
impersonateuserId: stringPromise<void>Start impersonating a user by their ID
stopImpersonating-Promise<void>Stop the current impersonation session

Type Definitions

interface User {
  id: string
  email: string
  name: string
  // ... other user properties
}

Usage Example

import { useImpersonation } from '@heimdall/nextjs'

export default function SupportDashboard() {
  const { isImpersonating, impersonatedUser, impersonate, stopImpersonating } = useImpersonation()

  const handleImpersonate = async (userId: string) => {
    try {
      await impersonate(userId)
      // Show success notification
    } catch (error) {
      // Handle error
    }
  }

  return (
    <div>
      {isImpersonating ? (
        <div>
          <h2>Impersonating: {impersonatedUser?.name}</h2>
          <button onClick={stopImpersonating}>
            Stop Impersonating
          </button>
        </div>
      ) : (
        <div>
          <h2>Support Dashboard</h2>
          {/* User list with impersonate buttons */}
        </div>
      )}
    </div>
  )
}

Best Practices

  1. Access Control: Only allow impersonation for users with appropriate permissions

    const { user } = useUser()
    const canImpersonate = user?.permissions.includes('impersonate')
    
  2. Clear Indicators: Always show when impersonation is active

    {isImpersonating && (
      <div className="impersonation-banner">
        Impersonating: {impersonatedUser?.name}
      </div>
    )}
    
  3. Error Handling: Handle impersonation errors gracefully

    try {
      await impersonate(userId)
    } catch (error) {
      if (error.code === 'PERMISSION_DENIED') {
        // Handle permission error
      } else if (error.code === 'USER_NOT_FOUND') {
        // Handle user not found
      }
    }
    
  4. Session Management: Ensure proper cleanup when stopping impersonation

    const handleStopImpersonating = async () => {
      try {
        await stopImpersonating()
        // Clear any cached data
        // Reset any user-specific state
      } catch (error) {
        // Handle error
      }
    }
    

Security Considerations

  1. Audit Logging: All impersonation actions should be logged
  2. Time Limits: Consider implementing session timeouts for impersonation
  3. Scope Limitation: Restrict what actions can be performed while impersonating
  4. Clear Boundaries: Maintain clear separation between real and impersonated sessions

API Routes

The hook interacts with the following API routes:

  1. POST /api/impersonate

    • Start impersonating a user
    • Requires userId in request body
    • Returns impersonated user data
  2. POST /api/impersonate/stop

    • Stop the current impersonation session
    • No request body required
    • Returns to original user session

For more detailed information about the impersonation system and its implementation, see the Impersonation documentation.

Usage Example

Here's a simple example of how to use these hooks in a NextJS component:

import { useAuth, useUser, useOrganization, useOrganizationSettings, useUserPermissions } from '@heimdall/nextjs'

export default function OrganizationSettingsPage() {
  const { isAuthenticated, login } = useAuth()
  const { organization } = useOrganization()
  const { settings, getSetting, setSetting } = useOrganizationSettings(organization?.id)
  const { hasPermission } = useUserPermissions()

  if (!isAuthenticated) {
    return <button onClick={login}>Login</button>
  }

  const canManageSettings = hasPermission('manage:organization', {
    organizationId: organization?.id
  })

  return (
    <div>
      <h1>Organization Settings</h1>

      <div>
        <h2>Domain Settings</h2>
        <div>
          <label>
            Allowed Domains:
            <input
              type="text"
              value={getSetting('allowedDomains')?.join(', ') || ''}
              onChange={(e) => setSetting('allowedDomains', e.target.value.split(',').map(d => d.trim()))}
              disabled={!canManageSettings}
            />
          </label>
        </div>
        <div>
          <label>
            Require Domain Match:
            <input
              type="checkbox"
              checked={getSetting('requireDomainMatch') || false}
              onChange={(e) => setSetting('requireDomainMatch', e.target.checked)}
              disabled={!canManageSettings}
            />
          </label>
        </div>
      </div>

      <div>
        <h2>Role Settings</h2>
        <div>
          <label>
            Default Role:
            <select
              value={getSetting('defaultRole') || ''}
              onChange={(e) => setSetting('defaultRole', e.target.value)}
              disabled={!canManageSettings}
            >
              <option value="">Select a role</option>
              <option value="member">Member</option>
              <option value="viewer">Viewer</option>
            </select>
          </label>
        </div>
      </div>
    </div>
  )
}

Error Handling

All hooks include error handling and will throw appropriate errors if authentication or API calls fail. Make sure to wrap your components in error boundaries or use try-catch blocks when necessary. See the Error Types documentation for more information about error handling.

Was this page helpful?