Skip to content

Authentication

IC Reactor provides seamless integration with Internet Identity for authentication. This guide covers everything you need to know about user authentication.

Authentication hooks are created by passing your ClientManager instance to createAuthHooks:

src/reactor/hooks.ts
import { createAuthHooks } from "@ic-reactor/react"
import { clientManager } from "./index"
export const { useAuth, useUserPrincipal, useAgentState } =
createAuthHooks(clientManager)

The primary hook for managing authentication. Provides login, logout, and access to the current identity and principal:

import { useAuth } from "../reactor/hooks"
function AuthButton() {
const { login, logout, isAuthenticated, isAuthenticating, principal } =
useAuth()
if (isAuthenticating) {
return <button disabled>Connecting...</button>
}
return isAuthenticated ? (
<button onClick={logout}>
Logout {principal?.toText().slice(0, 8)}...
</button>
) : (
<button onClick={() => login()}>Login with Internet Identity</button>
)
}

Customize the login flow with options:

const { login } = useAuth()
login({
// Identity provider URL (auto-detected based on network)
identityProvider: "https://identity.ic0.app",
// Session duration (default: 8 hours)
maxTimeToLive: BigInt(7 * 24 * 60 * 60 * 1_000_000_000), // 7 days
// Callbacks
onSuccess: () => {
console.log("Logged in!")
navigate("/dashboard")
},
onError: (error) => {
console.error("Login failed:", error)
toast.error("Authentication failed")
},
})

The ClientManager automatically selects the correct Internet Identity provider based on your network:

NetworkIdentity Provider
IC (mainnet)https://identity.ic0.app
Localhttp://localhost:4943?canisterId=rdmx6-jaaaa-aaaaa-aaadq-cai

You can override this by passing identityProvider to the login options.

A convenience hook to get the current user’s principal:

import { useUserPrincipal } from "../reactor/hooks"
function UserBadge() {
const principal = useUserPrincipal()
if (!principal || principal.isAnonymous()) {
return <span>Anonymous User</span>
}
return (
<span className="principal-badge">{principal.toText().slice(0, 8)}...</span>
)
}

Access the IC agent’s initialization state. This is useful for showing a global loading screen while the agent (and potential session) is warming up:

import { useAgentState } from "../reactor/hooks"
function AppRoot({ children }) {
const { isInitializing, error } = useAgentState()
if (isInitializing) {
return <LoadingScreen message="Connecting to IC..." />
}
if (error) {
return <ErrorScreen error={error} />
}
return children
}

Create a wrapper component for routes that require authentication:

import { useAuth } from "../reactor/hooks"
import { Navigate, useLocation } from "react-router-dom"
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isAuthenticating } = useAuth()
const location = useLocation()
// Show loading while checking auth state
if (isAuthenticating) {
return <LoadingSpinner />
}
// Redirect to login if not authenticated
if (!isAuthenticated) {
return <Navigate to="/login" state={{ from: location }} replace />
}
return <>{children}</>
}

Sessions are automatically persisted in IndexedDB. When users return to your app, the useAuth hook (or clientManager.initialize()) automatically triggers session restoration.

By default, Internet Identity sessions last 8 hours. You can customize this:

login({
maxTimeToLive: BigInt(7 * 24 * 60 * 60 * 1_000_000_000), // 7 days in nanoseconds
})

IC Reactor automatically invalidates all cached queries when the user’s identity changes. This ensures:

  • Login: Fresh data is fetched for the authenticated user
  • Logout: Cached user data is cleared immediately
  • Session restore: Queries are refreshed if a session is restored

This prevents cross-account data leakage and ensures data freshness.

If your app doesn’t need authentication, you can skip the @icp-sdk/auth package entirely. The ClientManager will work with an anonymous identity. Queries will work, but update calls requiring authentication will fail.