Skip to content
IC Reactor

useAuth

useAuth is the primary hook for authentication. It automatically initializes the client on mount and provides access to auth state and methods.

The first useAuth() to mount restores the previous session. Until that restore has settled, isAuthenticating is true: on the first render, in a server render, and while the stored session is read. So a component that shows a spinner while isAuthenticating never takes the state before the restore for a signed-out user. A restore that fails, such as one against a local replica that cannot be reached, settles it too.

import { useAuth } from "./reactor/hooks"
function AuthButton() {
const {
login, // Function to trigger login
logout, // Function to trigger logout
authenticate, // Function to authenticate without popup
isAuthenticated, // boolean
isAuthenticating, // boolean
identity, // Identity | null
principal, // Principal | null
error, // Error | undefined
} = useAuth()
return isAuthenticated ? (
<button onClick={() => logout()}>Logout {principal?.toText()}</button>
) : (
<button onClick={() => login()}>Login</button>
)
}

Triggers the Internet Identity login flow:

import { useAuth } from "./reactor/hooks"
function LoginButton() {
const { login } = useAuth()
return (
<button
onClick={() =>
login({
// Identity provider URL (auto-detected based on network)
identityProvider: "https://id.ai/authorize",
// Session duration in nanoseconds
maxTimeToLive: 8n * 60n * 60n * 1_000_000_000n,
// Callback on successful login
onSuccess: () => console.log("signed in"),
// Callback on login error
onError: (error) => console.error(error),
})
}
>
Login
</button>
)
}

Logs out and clears the session:

import { useAuth } from "./reactor/hooks"
function LogoutButton() {
const { logout } = useAuth()
// Clears session and updates state
return <button onClick={() => logout()}>Logout</button>
}

Restores an existing session without a popup. Resolves to the recovered Identity. With no session to restore it resolves to the auth client’s anonymous identity, so check isAuthenticated (or the principal) rather than the return value. It resolves undefined when the optional @icp-sdk/auth peer is not installed, or when it finds that a signed-in session has expired and ends it:

import { useAuth } from "./reactor/hooks"
function RestoreSessionButton() {
const { authenticate } = useAuth()
async function restore() {
const identity = await authenticate()
const signedIn =
identity !== undefined && !identity.getPrincipal().isAnonymous()
console.log(signedIn ? "Session restored" : "Signed out")
}
return <button onClick={restore}>Restore session</button>
}
Property Type Description
login (options?) => Promise<void> Triggers the login flow
logout (options?: { returnTo?: string }) => Promise<void> Logs the user out
authenticate () => Promise<Identity | undefined> Restores an existing session without a popup
isAuthenticated boolean Whether the user is currently authenticated
isAuthenticating boolean Whether the session is being restored, or a sign-in or sign-out is in progress
identity Identity | null The current user’s @icp-sdk/core/agent Identity
principal Principal | null The signed-in user’s @icp-sdk/core/principal Principal, or null while signed out
error Error | undefined Last authentication error

isAuthenticating covers the session restore, so this guard shows <Loading /> on a reload or deep link until the stored session has been read, and redirects only a user the restore found signed out:

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()
if (isAuthenticating) return <Loading />
if (!isAuthenticated) {
return <Navigate to="/login" state={{ from: location }} replace />
}
return <>{children}</>
}