AuthKit React
Add authentication to your React app with WorkOS AuthKit. Handles sign-in, sign-up, token refresh, and session management via a hosted OAuth flow.
Installation
npm install @workos-inc/authkit-react
Quick Start
1. Configure the WorkOS Dashboard
- Add a Redirect URI (e.g.
http://localhost:5173) on the Redirects page. This is where WorkOS sends users after they authenticate.
- Add your app's origin (e.g.
http://localhost:5173) to the allowed origins list on the Authentication page of the WorkOS Dashboard.
2. Wrap your app in AuthKitProvider
import { AuthKitProvider } from "@workos-inc/authkit-react";
import { createRoot } from "react-dom/client";
createRoot(document.getElementById("root")).render(
<AuthKitProvider clientId="client_01ABC123DEF456">
<App />
</AuthKitProvider>,
);
3. Add a /login route
Some authentication flows are initiated outside your app — for example, when an admin impersonates a user from the WorkOS Dashboard, or when a third-party triggers login via your app's sign-in endpoint. These flows redirect the user to a well-known login path in your app, which must then start the OAuth flow.
Register a /login URL (e.g. http://localhost:5173/login) as the sign-in endpoint on the same Redirects page, then handle it in your app:
import { useAuth } from "@workos-inc/authkit-react";
import { useEffect } from "react";
function LoginRoute() {
const { signIn } = useAuth();
useEffect(() => {
signIn();
}, [signIn]);
return <div>Redirecting...</div>;
}
In a router-based app this would be a dedicated route component. In a simple app you can handle it inline:
function App() {
const { isLoading, user, signIn } = useAuth();
useEffect(() => {
if (window.location.pathname === "/login") {
signIn();
}
}, [signIn]);
}
4. Use the useAuth hook
import { useAuth } from "@workos-inc/authkit-react";
function App() {
const { isLoading, user, signIn, signUp, signOut, getAccessToken } =
useAuth();
if (isLoading) return <div>Loading...</div>;
if (!user) {
return (
<div>
<button onClick={() => signIn()}>Sign In</button>
<button onClick={() => signUp()}>Sign Up</button>
</div>
);
}
return (
<div>
<p>Hello, {user.firstName ?? user.email}</p>
<button onClick={() => signOut()}>Sign Out</button>
</div>
);
}
That's it — you have a fully authenticated React app.
API Reference
<AuthKitProvider />
Wrap your app in this component to provide authentication context.
clientId | string | Yes | Your WorkOS Client ID (starts with client_) |
apiHostname | string | No | Your custom Authentication API domain. Defaults to api.workos.com. In production, this should be set to a domain you own (e.g. auth.example.com) |
devMode | boolean | No | Stores tokens in localStorage. Auto-enabled on localhost and 127.0.0.1. |
onRedirectCallback | (params) => void | No | Called after a successful authentication. Use to restore app state or navigate. |
onRefresh | (response) => void | No | Called when the access token is refreshed. |
onRefreshFailure | ({ signIn }) => void | No | Called when token refresh fails. Receives signIn to trigger re-authentication. |
onBeforeAutoRefresh | () => boolean | No | Called before automatic refresh. Return false to skip. |
refreshBufferInterval | number | No | Seconds before token expiration to trigger refresh. |
useAuth()
Returns the current auth state and helper methods. Must be called inside <AuthKitProvider>.
State
isLoading | boolean | true during initial authentication check |
user | User | null | The authenticated user, or null |
organizationId | string | null | The user's current organization |
role | string | null | The user's role in the current organization |
roles | string[] | null | All roles for the user in the current organization |
permissions | string[] | Permissions for the user's role |
featureFlags | string[] | Feature flags enabled for the organization |
impersonator | Impersonator | null | Set when an admin is impersonating this user |
authenticationMethod | AuthenticationMethod | null | How the user authenticated (e.g. "GoogleOAuth", "SSO") |
Methods
signIn | (opts?) => Promise<void> | Redirect to the AuthKit sign-in page |
signUp | (opts?) => Promise<void> | Redirect to the AuthKit sign-up page |
signOut | (opts?) => void | End the session and sign the user out |
getAccessToken | (opts?) => Promise<string> | Get a valid access token, refreshing if needed |
getUser | () => User | null | Synchronously get the current user |
switchToOrganization | ({ organizationId, signInOpts? }) => Promise<void> | Switch to a different organization |
getSignInUrl | (opts?) => Promise<string> | Get the sign-in URL without redirecting |
getSignUpUrl | (opts?) => Promise<string> | Get the sign-up URL without redirecting |
signIn / signUp Options
{
state?: any;
organizationId?: string;
loginHint?: string;
invitationToken?: string;
screenHint?: "sign-in" | "sign-up";
}
signOut Options
{
returnTo?: string;
}
User
interface User {
id: string;
email: string;
emailVerified: boolean;
profilePictureUrl: string | null;
firstName: string | null;
lastName: string | null;
createdAt: string;
updatedAt: string;
lastSignInAt: string | null;
externalId: string | undefined;
}
getClaims(accessToken)
Decodes a JWT access token and returns its claims.
import { getClaims } from "@workos-inc/authkit-react";
const token = await getAccessToken();
const claims = getClaims(token);
Error Classes
AuthKitError — Base error class for AuthKit errors.
LoginRequiredError — Thrown by getAccessToken() when no user is authenticated.
Recipes
Making Authenticated API Calls
function Dashboard() {
const { getAccessToken } = useAuth();
async function fetchData() {
const token = await getAccessToken();
const res = await fetch("/api/data", {
headers: { Authorization: `Bearer ${token}` },
});
return res.json();
}
}
Passing Data Through Auth Flows
Use state to preserve data across the authentication redirect:
<button onClick={() => signIn({ state: { returnTo: "/dashboard" } })}>
Sign In
</button>
<AuthKitProvider
clientId="client_01ABC123DEF456"
onRedirectCallback={({ state }) => {
if (state?.returnTo) {
window.location.href = state.returnTo;
}
}}
>
<App />
</AuthKitProvider>
Handling Token Refresh Failures
<AuthKitProvider
clientId="client_01ABC123DEF456"
onRefreshFailure={({ signIn }) => {
signIn();
}}
>
<App />
</AuthKitProvider>
Multi-Organization Switching
function OrgSwitcher({ organizations }) {
const { switchToOrganization, organizationId } = useAuth();
return (
<select
value={organizationId ?? ""}
onChange={(e) => switchToOrganization({ organizationId: e.target.value })}
>
{organizations.map((org) => (
<option key={org.id} value={org.id}>
{org.name}
</option>
))}
</select>
);
}
Role-Based UI
function AdminPanel() {
const { role, permissions } = useAuth();
if (role !== "admin") return null;
return (
<div>
<h2>Admin Panel</h2>
{permissions.includes("users:manage") && <UserManagement />}
</div>
);
}