ProjectsHanzoaiIamSdk
React Bindings
Drop-in React provider and hooks for Hanzo IAM — authentication, org switching, and token management.
React Bindings
@hanzo/iam/react provides a context provider and hooks that handle the full authentication lifecycle in React applications.
npm install @hanzo/iam reactIamProvider
Wrap your app with IamProvider to enable IAM authentication.
import { IamProvider } from "@hanzo/iam/react";
function App() {
return (
<IamProvider
config={{
serverUrl: "https://iam.hanzo.ai",
clientId: "my-app",
redirectUri: `${window.location.origin}/auth/callback`,
scope: "openid profile email", // optional, this is the default
storage: localStorage, // optional, default: sessionStorage
}}
autoInit={true} // check stored tokens on mount (default: true)
onAuthChange={(authed) => console.log("Auth:", authed)}
>
<MyApp />
</IamProvider>
);
}useIam
Access authentication state and methods.
import { useIam } from "@hanzo/iam/react";
function ProfileButton() {
const {
user, // IamUser | null
isAuthenticated, // boolean
isLoading, // boolean (initial auth check)
accessToken, // string | null
login, // (params?) => Promise<void>
loginPopup, // (params?) => Promise<void>
logout, // () => void
error, // Error | null
} = useIam();
if (isLoading) return <span>Loading...</span>;
if (!isAuthenticated) {
return <button onClick={() => login()}>Sign in</button>;
}
return (
<div>
<span>{user?.displayName || user?.email}</span>
<button onClick={logout}>Sign out</button>
</div>
);
}Login Methods
// Redirect to IAM login page (full-page redirect)
await login();
// Open IAM login in a popup (stays on current page)
await loginPopup({ width: 600, height: 700 });
// Pass additional OAuth params
await login({ additionalParams: { prompt: "consent" } });Callback Handling
On your callback route, use handleCallback to complete the OAuth flow:
import { useIam } from "@hanzo/iam/react";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
function AuthCallback() {
const { handleCallback } = useIam();
const navigate = useNavigate();
useEffect(() => {
handleCallback()
.then(() => navigate("/"))
.catch((err) => console.error("Auth failed:", err));
}, []);
return <p>Completing sign-in...</p>;
}useOrganizations
Manage organization and project switching. Selection persists to localStorage.
import { useOrganizations } from "@hanzo/iam/react";
function OrgSwitcher() {
const {
organizations, // IamOrganization[]
currentOrg, // IamOrganization | null
currentOrgId, // string | null
switchOrg, // (orgId: string) => void
currentProjectId, // string | null
switchProject, // (projectId: string | null) => void
isLoading, // boolean
} = useOrganizations();
if (isLoading) return <span>Loading orgs...</span>;
return (
<select
value={currentOrgId ?? ""}
onChange={(e) => switchOrg(e.target.value)}
>
{organizations.map((org) => (
<option key={org.name} value={org.name}>
{org.displayName || org.name}
</option>
))}
</select>
);
}How Org Resolution Works
- On authentication, the JWT
subclaim is parsed to extract the primary org - The SDK also attempts to fetch the full org list from the IAM API
- The current selection is persisted to
localStorage - Switching orgs clears the project selection
useIamToken
Get a valid access token with auto-refresh capability.
import { useIamToken } from "@hanzo/iam/react";
function ApiClient() {
const { token, isValid, refresh } = useIamToken();
const fetchData = async () => {
let currentToken = token;
if (!isValid) {
currentToken = await refresh();
}
const res = await fetch("/api/data", {
headers: { Authorization: `Bearer ${currentToken}` },
});
return res.json();
};
return <button onClick={fetchData}>Fetch Data</button>;
}Integration Pattern
Here's a complete integration showing auth, org switching, and a WebSocket gateway:
import { IamProvider, useIam, useOrganizations } from "@hanzo/iam/react";
function App() {
return (
<IamProvider config={iamConfig}>
<AuthGuard>
<Dashboard />
</AuthGuard>
</IamProvider>
);
}
function AuthGuard({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading, login } = useIam();
if (isLoading) return <div>Loading...</div>;
if (!isAuthenticated) {
return <button onClick={() => login()}>Sign in with Hanzo</button>;
}
return <>{children}</>;
}
function Dashboard() {
const { user, logout, accessToken } = useIam();
const { organizations, currentOrgId, switchOrg } = useOrganizations();
// Pass accessToken and currentOrgId to your gateway/API client
// When switchOrg is called, components re-render with the new context
return (
<header>
<OrgSwitcher orgs={organizations} current={currentOrgId} onSwitch={switchOrg} />
<span>{user?.displayName}</span>
<button onClick={logout}>Sign out</button>
</header>
);
}How is this guide?
Last updated on