React hooks for accessing authentication state, user data, and Clerk methods on the client side. All hooks are client-side only and require the 'use client' directive.
Required Setup:
'use client' directive (client components only)Default Behaviors:
useAuth() returns userId, sessionId, orgId as null when signed out, undefined when loadingisLoaded and isSignedIn properties indicate loading and authentication stategetToken() returns null if no session, Promise<string | null> for token retrievalhas() function checks permissions/roles synchronously (returns boolean)useUser() and useSession() return user/session as null when signed out, undefined when loadingnull when no active organizationundefined when not initializedThreading Model:
getToken() is async and must be awaitedsignOut(), setActive(), and other mutation methods are asynchas() are synchronousLifecycle:
getToken() fetches fresh token (can be cached)Edge Cases:
userId is undefined during initial load, null when signed outisLoaded: false means auth state is still loading (show loading UI)isSignedIn: false with isLoaded: true means user is signed outgetToken() can return null if session invalid or expiredhas() returns false if no active organization (even with permission)null organization when no active orgisLoaded check before using signIn/signUp objectsuseSessionList() returns empty array when no sessionsExceptions:
getToken() throws if Clerk not initializedReturns the current authentication state including user ID, session ID, organization data, and token management.
/**
* Returns authentication state and utilities
* @returns Authentication object with user/session IDs and methods
*/
function useAuth(): UseAuthReturn;
interface UseAuthReturn {
/** Current user ID, null if signed out, undefined if loading */
userId: string | null | undefined;
/** Current session ID, null if signed out, undefined if loading */
sessionId: string | null | undefined;
/** Current organization ID */
orgId: string | null | undefined;
/** Current user's role in the active organization */
orgRole: string | null | undefined;
/** Current organization slug */
orgSlug: string | null | undefined;
/** Current user's permissions in the active organization */
orgPermissions: string[] | null | undefined;
/** Actor identifier for impersonation scenarios */
actor: any | null | undefined;
/** Check if user has a specific permission */
has: (permission: string | { permission: string } | { role: string }) => boolean;
/** Get session token (promisified for Next.js) */
getToken: (options?: GetTokenOptions) => Promise<string | null>;
/** Sign out the current user */
signOut: () => Promise<void>;
/** True if authentication state is loaded */
isLoaded: boolean;
/** True if user is signed in */
isSignedIn: boolean;
}
interface GetTokenOptions {
/** Template name for custom JWT templates */
template?: string;
/** Skip cache and fetch fresh token */
skipCache?: boolean;
}Usage Example:
'use client';
import { useAuth } from '@clerk/nextjs';
export default function Component() {
const { userId, isLoaded, isSignedIn, getToken, has } = useAuth();
if (!isLoaded) {
return <div>Loading...</div>;
}
if (!isSignedIn) {
return <div>Not signed in</div>;
}
const handleGetToken = async () => {
const token = await getToken();
// Use token for API requests
};
const isAdmin = has({ role: 'admin' });
return <div>User ID: {userId}</div>;
}Returns the current User object with profile data and update methods.
/**
* Returns the current User object
* @returns User object and loading state
*/
function useUser(): UseUserReturn;
interface UseUserReturn {
/** True if user data is loaded */
isLoaded: boolean;
/** True if user is signed in */
isSignedIn: boolean;
/** User object, null if signed out, undefined if loading */
user: User | null | undefined;
}
interface User {
/** User's unique identifier */
id: string;
/** User's email addresses */
emailAddresses: EmailAddress[];
/** User's phone numbers */
phoneNumbers: PhoneNumber[];
/** User's external OAuth accounts */
externalAccounts: ExternalAccount[];
/** User's first name */
firstName: string | null;
/** User's last name */
lastName: string | null;
/** User's username */
username: string | null;
/** URL to user's profile image */
imageUrl: string;
/** Whether user has profile image */
hasImage: boolean;
/** User's primary email address */
primaryEmailAddress: EmailAddress | null;
/** User's primary phone number */
primaryPhoneNumber: PhoneNumber | null;
/** User's primary web3 wallet */
primaryWeb3Wallet: Web3Wallet | null;
/** User's unsafe metadata (client-readable, client-writable) */
unsafeMetadata: Record<string, any>;
/** User's public metadata (client-readable, admin-writable) */
publicMetadata: Record<string, any>;
/** Timestamp when user was created */
createdAt: Date;
/** Timestamp when user was last updated */
updatedAt: Date;
/** Update user profile */
update: (params: UpdateUserParams) => Promise<User>;
/** Reload user data */
reload: () => Promise<User>;
/** Delete user account */
delete: () => Promise<void>;
// Additional methods for managing email addresses, phone numbers, etc.
}Usage Example:
'use client';
import { useUser } from '@clerk/nextjs';
export default function UserProfile() {
const { isLoaded, isSignedIn, user } = useUser();
if (!isLoaded || !isSignedIn) {
return null;
}
return (
<div>
<h1>{user.firstName} {user.lastName}</h1>
<p>Email: {user.primaryEmailAddress?.emailAddress}</p>
<img src={user.imageUrl} alt="Profile" />
</div>
);
}Returns the current Session object with session data and methods.
/**
* Returns the current Session object
* @returns Session object and loading state
*/
function useSession(): UseSessionReturn;
interface UseSessionReturn {
/** True if session data is loaded */
isLoaded: boolean;
/** True if user is signed in */
isSignedIn: boolean;
/** Session object, null if signed out, undefined if loading */
session: Session | null | undefined;
}
interface Session {
/** Session's unique identifier */
id: string;
/** ID of the user this session belongs to */
userId: string;
/** Session status: 'active', 'expired', 'abandoned', 'removed' */
status: SessionStatus;
/** Timestamp of last activity */
lastActiveAt: Date;
/** Timestamp when session expires */
expireAt: Date;
/** Timestamp when session is abandoned */
abandonAt: Date;
/** Timestamp when session was created */
createdAt: Date;
/** Timestamp when session was last updated */
updatedAt: Date;
/** Active organization ID */
lastActiveOrganizationId: string | null;
/** Active organization slug */
lastActiveOrganizationSlug: string | null;
/** Active organization role */
lastActiveOrganizationRole: string | null;
/** Actor identifier for impersonation */
actor: any | null;
/** Get session token */
getToken: (options?: GetTokenOptions) => Promise<string | null>;
/** Check authorization */
checkAuthorization: (params: CheckAuthorizationParams) => boolean;
/** Reload session data */
reload: () => Promise<Session>;
/** End session */
end: () => Promise<Session>;
}Usage Example:
'use client';
import { useSession } from '@clerk/nextjs';
export default function SessionInfo() {
const { isLoaded, session } = useSession();
if (!isLoaded) {
return <div>Loading...</div>;
}
return (
<div>
<p>Status: {session?.status}</p>
<p>Last Active: {session?.lastActiveAt.toLocaleString()}</p>
</div>
);
}Returns the Clerk instance with methods for managing authentication and navigation.
/**
* Returns the Clerk instance
* @returns Clerk instance with authentication methods
*/
function useClerk(): Clerk;
interface Clerk {
/** Loaded state */
loaded: boolean;
/** Current user object */
user: User | null | undefined;
/** Current session object */
session: Session | null | undefined;
/** Current organization object */
organization: Organization | null | undefined;
/** Open sign-in modal or navigate to sign-in page */
openSignIn: (props?: SignInProps) => void;
/** Open sign-up modal or navigate to sign-up page */
openSignUp: (props?: SignUpProps) => void;
/** Open user profile modal or navigate to user profile page */
openUserProfile: () => void;
/** Open organization profile modal or navigate to organization profile page */
openOrganizationProfile: () => void;
/** Close current modal */
closeModal: () => void;
/** Sign out the current user */
signOut: (options?: SignOutOptions) => Promise<void>;
/** Set active session */
setActive: (params: SetActiveParams) => Promise<void>;
/** Navigate to a URL */
navigate: (to: string) => Promise<unknown>;
/** Build URL with Clerk parameters */
buildUrl: (to: string, options?: BuildUrlOptions) => string;
}Usage Example:
'use client';
import { useClerk } from '@clerk/nextjs';
export default function AuthButtons() {
const clerk = useClerk();
return (
<div>
<button onClick={() => clerk.openSignIn()}>Sign In</button>
<button onClick={() => clerk.openSignUp()}>Sign Up</button>
<button onClick={() => clerk.signOut()}>Sign Out</button>
</div>
);
}Returns the current Organization object and methods for managing members and invitations.
/**
* Returns the current Organization object
* @returns Organization object, membership, and management methods
*/
function useOrganization(): UseOrganizationReturn;
interface UseOrganizationReturn {
/** True if organization data is loaded */
isLoaded: boolean;
/** Current organization object */
organization: Organization | null | undefined;
/** Current user's membership in the organization */
membership: OrganizationMembership | null | undefined;
/** List of organization memberships (paginated) */
memberships: PaginatedResources<OrganizationMembership>;
/** List of organization invitations (paginated) */
invitations: PaginatedResources<OrganizationInvitation>;
}
interface Organization {
/** Organization's unique identifier */
id: string;
/** Organization name */
name: string;
/** Organization slug */
slug: string;
/** URL to organization's logo image */
imageUrl: string;
/** Whether organization has logo */
hasImage: boolean;
/** Number of members */
membersCount: number;
/** Number of pending invitations */
pendingInvitationsCount: number;
/** Organization's public metadata */
publicMetadata: Record<string, any>;
/** Timestamp when organization was created */
createdAt: Date;
/** Timestamp when organization was last updated */
updatedAt: Date;
/** Update organization */
update: (params: UpdateOrganizationParams) => Promise<Organization>;
/** Delete organization */
destroy: () => Promise<void>;
/** Get memberships */
getMemberships: (params?: GetMembershipsParams) => Promise<OrganizationMembership[]>;
/** Add member */
addMember: (params: AddMemberParams) => Promise<OrganizationMembership>;
/** Invite member */
inviteMember: (params: InviteMemberParams) => Promise<OrganizationInvitation>;
/** Update member */
updateMember: (params: UpdateMemberParams) => Promise<OrganizationMembership>;
/** Remove member */
removeMember: (userId: string) => Promise<OrganizationMembership>;
/** Reload organization data */
reload: () => Promise<Organization>;
}Usage Example:
'use client';
import { useOrganization } from '@clerk/nextjs';
export default function OrganizationDashboard() {
const { isLoaded, organization, memberships } = useOrganization();
if (!isLoaded) {
return <div>Loading...</div>;
}
if (!organization) {
return <div>No organization selected</div>;
}
return (
<div>
<h1>{organization.name}</h1>
<p>Members: {organization.membersCount}</p>
<ul>
{memberships.data?.map((membership) => (
<li key={membership.id}>{membership.publicUserData.identifier}</li>
))}
</ul>
</div>
);
}Returns a list of organizations the user belongs to with methods for creating and switching organizations.
/**
* Returns list of user's organizations
* @returns Organization list and management methods
*/
function useOrganizationList(): UseOrganizationListReturn;
interface UseOrganizationListReturn {
/** True if organization list is loaded */
isLoaded: boolean;
/** List of user's organization memberships */
userMemberships: PaginatedResources<OrganizationMembership>;
/** List of user's organization invitations */
userInvitations: PaginatedResources<OrganizationInvitation>;
/** Set active organization or session */
setActive: (params: SetActiveParams) => Promise<void>;
/** Create new organization */
createOrganization: (params: CreateOrganizationParams) => Promise<Organization>;
}
interface SetActiveParams {
/** Session ID to set as active */
session?: string | Session | null;
/** Organization ID to set as active */
organization?: string | Organization | null;
/** Callback before setting active */
beforeEmit?: (session?: Session | null) => void | Promise<any>;
}Usage Example:
'use client';
import { useOrganizationList } from '@clerk/nextjs';
export default function OrganizationSelector() {
const { isLoaded, userMemberships, setActive } = useOrganizationList();
if (!isLoaded) {
return <div>Loading...</div>;
}
return (
<select
onChange={(e) => setActive({ organization: e.target.value })}
>
{userMemberships.data?.map((membership) => (
<option key={membership.id} value={membership.organization.id}>
{membership.organization.name}
</option>
))}
</select>
);
}Returns sign-in methods and state for building custom sign-in flows.
/**
* Returns sign-in methods and state
* @returns SignIn object for managing sign-in flow
*/
function useSignIn(): UseSignInReturn;
interface UseSignInReturn {
/** True if sign-in data is loaded */
isLoaded: boolean;
/** SignIn object */
signIn: SignIn | undefined;
/** Set active session after sign-in */
setActive: (params: SetActiveParams) => Promise<void>;
}
interface SignIn {
/** Sign-in status */
status: SignInStatus;
/** Supported identifiers */
supportedIdentifiers: string[];
/** Supported first factors */
supportedFirstFactors: SignInFactor[];
/** Supported second factors */
supportedSecondFactors: SignInFactor[];
/** Create sign-in with identifier and password */
create: (params: SignInCreateParams) => Promise<SignIn>;
/** Verify with strategy */
prepareFirstFactor: (params: PrepareFirstFactorParams) => Promise<SignIn>;
/** Attempt first factor verification */
attemptFirstFactor: (params: AttemptFirstFactorParams) => Promise<SignIn>;
/** Prepare second factor */
prepareSecondFactor: (params: PrepareSecondFactorParams) => Promise<SignIn>;
/** Attempt second factor verification */
attemptSecondFactor: (params: AttemptSecondFactorParams) => Promise<SignIn>;
/** Reload sign-in object */
reload: () => Promise<SignIn>;
}Usage Example:
'use client';
import { useSignIn } from '@clerk/nextjs';
import { useState } from 'react';
export default function CustomSignIn() {
const { isLoaded, signIn, setActive } = useSignIn();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!isLoaded) return;
try {
const result = await signIn.create({
identifier: email,
password,
});
if (result.status === 'complete') {
await setActive({ session: result.createdSessionId });
}
} catch (err) {
console.error('Sign in error:', err);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign In</button>
</form>
);
}Returns sign-up methods and state for building custom sign-up flows.
/**
* Returns sign-up methods and state
* @returns SignUp object for managing sign-up flow
*/
function useSignUp(): UseSignUpReturn;
interface UseSignUpReturn {
/** True if sign-up data is loaded */
isLoaded: boolean;
/** SignUp object */
signUp: SignUp | undefined;
/** Set active session after sign-up */
setActive: (params: SetActiveParams) => Promise<void>;
}
interface SignUp {
/** Sign-up status */
status: SignUpStatus;
/** Required fields */
requiredFields: string[];
/** Optional fields */
optionalFields: string[];
/** Missing fields */
missingFields: string[];
/** Unverified fields */
unverifiedFields: string[];
/** Verifications */
verifications: SignUpVerifications;
/** Username */
username: string | null;
/** Email address */
emailAddress: string | null;
/** Phone number */
phoneNumber: string | null;
/** First name */
firstName: string | null;
/** Last name */
lastName: string | null;
/** Unsafe metadata */
unsafeMetadata: Record<string, any>;
/** Created session ID */
createdSessionId: string | null;
/** Created user ID */
createdUserId: string | null;
/** Create sign-up */
create: (params: SignUpCreateParams) => Promise<SignUp>;
/** Update sign-up */
update: (params: SignUpUpdateParams) => Promise<SignUp>;
/** Prepare verification */
prepareVerification: (params: PrepareVerificationParams) => Promise<SignUp>;
/** Attempt verification */
attemptVerification: (params: AttemptVerificationParams) => Promise<SignUp>;
/** Reload sign-up object */
reload: () => Promise<SignUp>;
}Usage Example:
'use client';
import { useSignUp } from '@clerk/nextjs';
import { useState } from 'react';
export default function CustomSignUp() {
const { isLoaded, signUp, setActive } = useSignUp();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [code, setCode] = useState('');
const [verifying, setVerifying] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!isLoaded) return;
try {
await signUp.create({
emailAddress: email,
password,
});
await signUp.prepareVerification({ strategy: 'email_code' });
setVerifying(true);
} catch (err) {
console.error('Sign up error:', err);
}
};
const handleVerify = async (e: React.FormEvent) => {
e.preventDefault();
if (!isLoaded) return;
try {
const result = await signUp.attemptVerification({ code });
if (result.status === 'complete') {
await setActive({ session: result.createdSessionId });
}
} catch (err) {
console.error('Verification error:', err);
}
};
if (verifying) {
return (
<form onSubmit={handleVerify}>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="Verification code"
/>
<button type="submit">Verify</button>
</form>
);
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign Up</button>
</form>
);
}Returns a list of the user's active sessions with methods for switching sessions.
/**
* Returns list of user's sessions
* @returns Session list and management methods
*/
function useSessionList(): UseSessionListReturn;
interface UseSessionListReturn {
/** True if session list is loaded */
isLoaded: boolean;
/** List of user's sessions */
sessions: Session[] | undefined;
/** Set active session */
setActive: (params: SetActiveParams) => Promise<void>;
}Usage Example:
'use client';
import { useSessionList } from '@clerk/nextjs';
export default function SessionManager() {
const { isLoaded, sessions, setActive } = useSessionList();
if (!isLoaded) {
return <div>Loading...</div>;
}
return (
<div>
<h2>Active Sessions</h2>
{sessions?.map((session) => (
<div key={session.id}>
<p>Last active: {session.lastActiveAt.toLocaleString()}</p>
<button onClick={() => setActive({ session: session.id })}>
Switch to this session
</button>
</div>
))}
</div>
);
}Returns utilities for email link verification flows.
/**
* Returns email link verification utilities
* @returns Email link methods
*/
function useEmailLink(): UseEmailLinkReturn;
interface UseEmailLinkReturn {
/** Start email link flow */
startEmailLinkFlow: (params: StartEmailLinkFlowParams) => Promise<void>;
/** Cancel email link flow */
cancelEmailLinkFlow: () => void;
}Returns reverification utilities for sensitive operations.
/**
* Returns reverification utilities
* @returns Reverification methods and state
*/
function useReverification(): UseReverificationReturn;
interface UseReverificationReturn {
/** Reverify user for sensitive operation */
reverify: () => Promise<void>;
/** Reverification status */
status: 'idle' | 'loading' | 'success' | 'error';
}interface PaginatedResources<T> {
data: T[] | undefined;
count: number | undefined;
isLoading: boolean;
isFetching: boolean;
isError: boolean;
page: number;
pageCount: number | undefined;
fetchNext: () => Promise<void>;
fetchPrevious: () => Promise<void>;
hasNextPage: boolean;
hasPreviousPage: boolean;
revalidate: () => Promise<void>;
setPage: (page: number) => void;
}