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 authenticatedlogin: Function to initiate the login flowlogout: 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 informationisLoading: 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 usergetOrganization(organizationId: string): Fetches details for a specific organizationcreateOrganization(data: CreateOrganizationData): Creates a new organizationupdateOrganization(organizationId: string, data: UpdateOrganizationData): Updates an organization's detailsdeleteOrganization(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 organizationcreateTeam(teamData): Creates a new team in the organizationdeleteTeam(teamId): Deletes a team from the organizationleaveTeam(teamId): Removes the current user from a teaminviteUser(teamId, email, role): Sends an invitation to join a teamremoveUser(teamId, userId): Removes a user from a teamcancelInvite(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 systemlistUserPermissions(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 systemuserRoles: Array of roles assigned to the current userisLoading: Boolean indicating if role data is being loaded
Methods
listRoles(): Fetches all available roles in the systemlistUserRoles(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 organizationgetSetting(key: string): Fetches a specific setting valuesetSetting(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 settingsisLoading: Boolean indicating if settings data is being loaded
Methods
getSettings(): Fetches all settings for the usergetSetting(key: string): Fetches a specific setting valuesetSetting(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
| Property | Type | Description |
|---|---|---|
features | Feature[] | List of all available features |
isLoading | boolean | Whether the features are currently loading |
Methods
| Method | Parameters | Return Type | Description |
|---|---|---|---|
isEnabled | featureKey: string | boolean | Check if a specific feature is enabled |
getFeature | featureKey: string | Feature | undefined | Get 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:
-
Boolean Flags: Simple on/off toggles
const isEnabled = isEnabled('new-feature') -
String Flags: For configuration values
const theme = getFeature('theme')?.value -
Number Flags: For numeric configurations
const maxItems = getFeature('max-items')?.value -
JSON Flags: For complex configurations
const config = getFeature('advanced-config')?.value
Best Practices
-
Default Values: Always provide fallbacks for when features are not enabled
const isEnabled = isEnabled('new-feature') ?? false -
Type Safety: Use TypeScript to ensure type safety with feature values
const maxItems = (getFeature('max-items')?.value as number) ?? 10 -
Loading States: Handle loading states appropriately
if (isLoading) { return <LoadingSpinner /> } -
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:
- A/B Testing: Support for A/B testing configurations
- User Targeting: Feature flags based on user properties
- Time-based Flags: Scheduled feature releases
- Percentage Rollouts: Gradual feature rollouts
- Environment-specific Flags: Different configurations per environment
- Audit Logging: Track feature flag changes
- 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
| Property | Type | Description |
|---|---|---|
isImpersonating | boolean | Whether a user is currently being impersonated |
impersonatedUser | User | null | The user being impersonated, if any |
Methods
| Method | Parameters | Return Type | Description |
|---|---|---|---|
impersonate | userId: string | Promise<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
-
Access Control: Only allow impersonation for users with appropriate permissions
const { user } = useUser() const canImpersonate = user?.permissions.includes('impersonate') -
Clear Indicators: Always show when impersonation is active
{isImpersonating && ( <div className="impersonation-banner"> Impersonating: {impersonatedUser?.name} </div> )} -
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 } } -
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
- Audit Logging: All impersonation actions should be logged
- Time Limits: Consider implementing session timeouts for impersonation
- Scope Limitation: Restrict what actions can be performed while impersonating
- Clear Boundaries: Maintain clear separation between real and impersonated sessions
API Routes
The hook interacts with the following API routes:
-
POST /api/impersonate
- Start impersonating a user
- Requires
userIdin request body - Returns impersonated user data
-
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.
