@mpofusindie/iam-react
v1.3.1
Published
React hooks and guard components for IAM service
Downloads
871
Readme
@mpofusindie/iam-react
React hooks and guard components for the IAM (Identity & Access Management) service. Provides declarative, permission-based UI rendering with OAuth2/OIDC authentication, two-factor authentication, password reset, and session management.
Install
npm install @mpofusindie/iam-reactPeer dependencies: react >= 18.0.0, react-dom >= 18.0.0, react-router-dom >= 6.0.0
Quick Start
1. Wrap your app with IAMProvider
import { IAMProvider } from "@mpofusindie/iam-react";
function App() {
return (
<IAMProvider
config={{
apiUrl: "/api/iam/v1",
token: jwtToken,
tenantId: "optional-tenant-uuid", // for header-based multi-tenancy
refreshMode: "body", // "body" | "cookie" | "both"
}}
loadingFallback={<Spinner />}
>
<YourApp />
</IAMProvider>
);
}2. Guard your routes
import { ProtectedRoute } from "@mpofusindie/iam-react";
<Route path="/loans" element={
<ProtectedRoute resource="loans">
<LoansPage />
</ProtectedRoute>
} />3. Guard features, actions, and fields
import { FeatureGuard, ActionGuard, FieldGuard } from "@mpofusindie/iam-react";
{/* Show nav item only if user has access to loans */}
<FeatureGuard resource="loans">
<NavLink to="/loans">Loans</NavLink>
</FeatureGuard>
{/* Show button only if user can create loans */}
<ActionGuard resource="loans" action="create">
<button>Create Loan</button>
</ActionGuard>
{/* Show button but disabled if no permission */}
<ActionGuard resource="loans" action="approve" mode="disable">
<button>Approve</button>
</ActionGuard>
{/* Mask sensitive fields */}
<FieldGuard resource="loans" field="ssn" maskChar="***-**-****">
{loan.ssn}
</FieldGuard>4. OAuth2 Login
import { useOAuth2, OAuth2LoginButton, OAuth2Callback } from "@mpofusindie/iam-react";
{/* Show provider buttons */}
<OAuth2LoginButton providerKey="google" label="Sign in with Google" />
{/* Handle callback */}
<Route path="/auth/callback" element={
<OAuth2Callback onSuccess={handleTokens} onError={handleError} />
} />5. Two-Factor Authentication
import { useTwoFactor, TwoFactorSetup, TwoFactorVerify } from "@mpofusindie/iam-react";
function TwoFactorPage() {
const { setup, confirmSetup, verify, disable } = useTwoFactor();
// Setup: generates QR code + backup codes
const setupData = await setup();
return (
<TwoFactorSetup
setupData={setupData}
onConfirm={(code) => confirmSetup(code)}
/>
);
}
// During login challenge (requires2fa === true):
<TwoFactorVerify
onSubmit={(code) => verify(challengeToken, code)}
onVerified={(tokenPair) => handleLogin(tokenPair)}
/>6. Password Reset
import { usePasswordReset, PasswordResetForm } from "@mpofusindie/iam-react";
const { forgotPassword, resetPassword } = usePasswordReset();
<PasswordResetForm
onForgotPassword={(email) => forgotPassword(email)}
onResetPassword={(token, password) => resetPassword(token, password)}
onResetComplete={() => navigate("/login")}
/>7. Session Management
import { useSessions } from "@mpofusindie/iam-react";
const { revokeUserSessions, revokeTenantSessions } = useSessions();
// Revoke all sessions for a specific user
await revokeUserSessions(userId);
// Emergency: revoke all sessions for the entire tenant
await revokeTenantSessions();8. Programmatic Permission Checks
import { usePermissions } from "@mpofusindie/iam-react";
function LoansTable() {
const { canDo, isFieldVisible, hasRole } = usePermissions();
const columns = baseColumns.filter(
col => !col.field || isFieldVisible("loans", col.field)
);
return (
<div>
{canDo("loans", "export") && <ExportButton />}
<Table columns={columns} data={loans} />
</div>
);
}9. Admin Management API
import { useIAMAdmin } from "@mpofusindie/iam-react";
const admin = useIAMAdmin();
// CRUD operations
const users = await admin.users.list({ page: 0, size: 20 });
const role = await admin.roles.create({ name: "MANAGER", description: "..." });
// OAuth2 providers
const providers = await admin.oauth2Providers.list();
await admin.oauth2Providers.create({ providerKey: "google", ... });
// Audit logs
const logs = await admin.auditLogs.list({ entityType: "USER", from: "2026-01-01" });
const csvBlob = await admin.auditLogs.export("csv", { entityType: "USER" });
// Session management
await admin.sessions.revokeUser(userId);
await admin.sessions.revokeTenant();API Reference
Components
| Component | Props | Description |
|-----------|-------|-------------|
| IAMProvider | config, loadingFallback?, onError? | Permission context provider |
| FeatureGuard | resource, fallback? | Show children if resource access granted |
| ActionGuard | resource, action, mode?, fallback? | Show/disable based on action permission |
| FieldGuard | resource, field, fallback?, maskChar? | Show/mask based on field visibility |
| ProtectedRoute | resource, redirectTo? | Redirect if access denied |
| OAuth2LoginButton | providerKey, label?, icon?, className? | OAuth2 provider login button |
| OAuth2Callback | onSuccess, onError, loadingComponent? | OAuth2 callback handler |
| TwoFactorSetup | setupData, onConfirm, onError?, className? | 2FA QR code + backup codes + confirm |
| TwoFactorVerify | onSubmit, onVerified, onError?, className? | TOTP code input for login challenge |
| PasswordResetForm | onForgotPassword, onResetPassword, onResetComplete?, className? | Two-step password reset form |
Hooks
| Hook | Returns | Description |
|------|---------|-------------|
| usePermissions() | { permissions, loading, canAccess, canDo, isFieldVisible, hasRole, ... } | Permission state and helpers |
| useIAMAdmin() | { users, roles, groups, resources, actions, permissions, oauth2Providers, auditLogs, sessions } | Typed CRUD + admin operations |
| useOAuth2() | { providers, loading, loginWith, completeAuth, exchangeToken } | OAuth2 authentication flow |
| useTwoFactor() | { setup, confirmSetup, verify, disable, regenerateBackupCodes } | 2FA lifecycle management |
| usePasswordReset() | { forgotPassword, resetPassword } | Password reset flow |
| useSessions() | { revokeUserSessions, revokeTenantSessions } | Session revocation |
Types
import type {
ResolvedPermissions,
FeatureAccess,
FieldAccess,
ActionPermissions,
IAMConfig,
RefreshMode,
TokenPair,
OAuth2Provider,
UserAuthProviderInfo,
TwoFactorSetupResponse,
AuditLogEntry,
} from "@mpofusindie/iam-react";IAMConfig
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| apiUrl | string | required | IAM backend base URL |
| token | string | required | JWT access token |
| refreshInterval? | number | — | Auto-refresh interval (ms) |
| refreshMode? | RefreshMode | "body" | Refresh token delivery: "body", "cookie", or "both" |
| tenantId? | string | — | Tenant UUID for header-based multi-tenancy |
How It Works
IAMProviderfetchesGET /me/permissionsfrom your IAM backend on mount- Permissions are cached in React state with TTL-based auto-refresh
- Guard components read permissions from context and conditionally render children
- 2FA/OAuth2/password reset hooks call the corresponding backend endpoints
- No access logic in your components — guards handle everything declaratively
Design Principles
- Server is the source of truth — frontend never determines access, only renders what the backend permits
- Zero access logic in components — use guards, not
if (role === "admin") - Three-tier permissions — feature-level, action-level, field-level
- DENY wins — if any role denies access, it's denied regardless of other roles
- Implicit deny — no permission = no access
- Components accept callbacks — 2FA and password reset components are decoupled from transport
Backend
This library works with the IAM Spring Boot Starter:
implementation("dev.mpofusindie:iam-spring-boot-starter:1.2.0")The backend provides:
- JWT authentication + OAuth2/OIDC (Google, Microsoft, any OIDC provider)
- TOTP two-factor authentication with backup codes
- Permission resolution with three-tier access control
- Password reset with session invalidation
- Multi-tenant support (JWT, header, subdomain resolution)
- Management APIs for users, roles, groups, resources, permissions, OAuth2 providers
- Audit logging with export and retention
- Rate limiting (in-memory or Redis)
Troubleshooting
Blank page after login
IAMProvider calls GET /me/permissions on mount. If the request fails, no permissions are loaded and guard components render nothing. Check:
- Is the JWT token valid and not expired? Look for
401errors in the browser console. - Is
apiUrlinIAMConfigpointing to the correct backend URL? - Is the backend running and reachable from the browser?
401 after token expiry
Access tokens expire after 15 minutes by default. After expiry, permission fetches return 401 and guards stop rendering. Use the refresh token flow (refreshMode in IAMConfig) to obtain new tokens automatically, or redirect the user to re-authenticate.
Guards not rendering children
If a guard component renders nothing even though the user should have access:
- Check
usePermissions().loading— guards returnnullwhile permissions are still loading. - Verify the
resourceprop matches the resource code configured in the backend exactly (case-sensitive). - For
ActionGuard, verify theactionprop matches the backend action code. - For
FieldGuard, verify thefieldprop matches the backend field name.
OAuth2 callback blank page
React StrictMode double-mounts components in development, which can cause the OAuth2 callback to fire twice. Ensure your onSuccess handler in OAuth2Callback is idempotent — exchanging the same authorization code twice will fail on the second attempt.
CORS errors
If the browser console shows CORS errors when calling the IAM backend, the backend must include your frontend origin in its allowed origins configuration:
iam:
security:
cors-allowed-origins:
- http://localhost:3000
- https://your-frontend-domain.comLicense
MIT
