From inai-auth-skills
Integrate InAI Auth SDK into React applications. Use this skill whenever the user wants to add authentication UI, auth hooks, login/signup components, role-based rendering, or session management to a React app using @inai-dev/react. Also trigger when the user mentions InAI auth with React, asks about auth hooks (useAuth, useUser, useSignIn, useSignUp), needs pre-built auth components (SignIn, UserButton, SignedIn, SignedOut, Protect), wants context-based auth state, or is building React islands in Astro that need authentication. This is the client-side React package — for Next.js use @inai-dev/nextjs, for Astro use @inai-dev/astro.
How this skill is triggered — by the user, by Claude, or both
Slash command
/inai-auth-skills:inai-react-sdkThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill guides you through integrating InAI Auth into React applications using the `@inai-dev/react` package. This is the client-side React package — it provides the context provider, hooks, and pre-built components that all other framework SDKs build upon.
This skill guides you through integrating InAI Auth into React applications using the @inai-dev/react package. This is the client-side React package — it provides the context provider, hooks, and pre-built components that all other framework SDKs build upon.
https://apiauth.inai.dev — hardcoded in the SDK, never configurable@inai-dev/reactreact >= 18.0.0auth_session cookie on mount (set by server-side auth routes)@inai-dev/nextjs, @inai-dev/astro, @inai-dev/express, or @inai-dev/hono for server-side authnpm install @inai-dev/react
<InAIAuthProvider> wrapping your appuseAuth(), useUser(), useSignIn(), useSignUp(), useSession(), useOrganization()<SignIn>, <UserButton>, <SignedIn>, <SignedOut>, <Protect>, <PermissionGate>, <OrganizationSwitcher>import { InAIAuthProvider } from "@inai-dev/react";
function App() {
return (
<InAIAuthProvider>
<YourApp />
</InAIAuthProvider>
);
}
The provider is zero-config. On mount, it reads the auth_session cookie (set by server-side auth routes) to hydrate client-side auth state without a network request.
document.cookie for auth_sessionisLoaded = true and broadcasts state to all child hooks/componentsisLoaded = true, isSignedIn = falseAll hooks require <InAIAuthProvider> as an ancestor.
Core hook for authentication state and actions.
import { useAuth } from "@inai-dev/react";
function MyComponent() {
const { isLoaded, isSignedIn, userId, roles, permissions, has, signOut } = useAuth();
if (!isLoaded) return <LoadingSpinner />;
if (!isSignedIn) return <a href="/login">Sign in</a>;
const isAdmin = has({ role: "admin" });
const canEdit = has({ permission: "posts:write" });
return (
<div>
<p>User: {userId}</p>
{isAdmin && <a href="/admin">Admin Panel</a>}
<button onClick={signOut}>Sign Out</button>
</div>
);
}
Returns: { isLoaded, isSignedIn, userId, roles, permissions, has, signOut }
has({ role?: string; permission?: string }): boolean — check role or permissionroles: string[] — array of the user's assigned rolespermissions: string[] — array of the user's granted permissionssignOut(): Promise<void> — calls /api/auth/logout, clears state, redirects to /loginReturns user profile data.
import { useUser } from "@inai-dev/react";
function Profile() {
const { isLoaded, isSignedIn, user } = useUser();
if (!isLoaded || !isSignedIn) return null;
return (
<div>
<img src={user.avatarUrl} alt={user.firstName} />
<h2>{user.firstName} {user.lastName}</h2>
<p>{user.email}</p>
</div>
);
}
Returns: { isLoaded, isSignedIn, user: UserResource | null }
Returns session and organization context.
import { useSession } from "@inai-dev/react";
function SessionInfo() {
const { isLoaded, isSignedIn, userId, tenantId, orgId, orgRole, roles, permissions } = useSession();
// ...
}
Returns: { isLoaded, isSignedIn, userId, tenantId, orgId, orgRole, roles, permissions }
Returns only organization-scoped data.
import { useOrganization } from "@inai-dev/react";
function OrgInfo() {
const { isLoaded, orgId, orgRole } = useOrganization();
// ...
}
Returns: { isLoaded, orgId, orgRole }
Handles the complete sign-in flow, including MFA.
import { useSignIn } from "@inai-dev/react";
function LoginForm() {
const { signIn, isLoading, error, status, reset } = useSignIn();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const result = await signIn.create({
identifier: email,
password,
});
if (result.status === "needs_mfa") {
// Show MFA form — mfa_token is stored internally
} else if (result.status === "complete") {
window.location.href = "/dashboard";
}
};
const handleMFA = async (code: string) => {
const result = await signIn.attemptMFA({ code });
if (result.status === "complete") {
window.location.href = "/dashboard";
}
};
// ...
}
Returns: { signIn, isLoading, error, status, reset }
status: "idle" | "loading" | "needs_mfa" | "complete" | "error"signIn.create({ identifier, password }) — initial login attemptsignIn.attemptMFA({ code }) — verify TOTP MFA codereset() — reset state to idleHandles registration flow with email verification support.
import { useSignUp } from "@inai-dev/react";
function RegisterForm() {
const { signUp, isLoading, error, status, reset } = useSignUp();
const handleSubmit = async () => {
const result = await signUp.create({
email,
password,
firstName,
lastName,
});
if (result.status === "needs_email_verification") {
// Show "check your email" message
} else if (result.status === "complete") {
window.location.href = "/dashboard";
}
};
// ...
}
Returns: { signUp, isLoading, error, status, reset }
status: "idle" | "loading" | "needs_email_verification" | "complete" | "error"Conditional rendering based on auth state.
import { SignedIn, SignedOut } from "@inai-dev/react";
function Navbar() {
return (
<nav>
<SignedIn>
<UserButton showName afterSignOutUrl="/login" />
</SignedIn>
<SignedOut>
<a href="/login">Sign in</a>
</SignedOut>
</nav>
);
}
<SignedIn> — renders children only when isLoaded && isSignedIn<SignedOut> — renders children only when isLoaded && !isSignedInRole/permission gate.
import { Protect } from "@inai-dev/react";
<Protect role="admin" fallback={<p>Access denied</p>}>
<AdminPanel />
</Protect>
<Protect permission="posts:write">
<Editor />
</Protect>
Props: { role?, permission?, fallback?, children }
Alternative permission-based gate (same behavior as Protect).
import { PermissionGate } from "@inai-dev/react";
<PermissionGate permission="billing:manage" fallback={<p>No access</p>}>
<BillingSettings />
</PermissionGate>
Props: { permission?, role?, fallback?, children }
Avatar dropdown with user info and sign-out.
import { UserButton } from "@inai-dev/react";
<UserButton
afterSignOutUrl="/"
showName
menuItems={[
{ label: "Settings", onClick: () => router.push("/settings") },
{ label: "Profile", onClick: () => router.push("/profile") },
]}
appearance={{
buttonSize: 36,
buttonBg: "#1a1a2e",
menuBg: "#1a1a1a",
menuBorder: "#333",
}}
/>
Props:
afterSignOutUrl?: string — redirect after sign outshowName?: boolean — display user name next to avatarmenuItems?: { label: string; onClick: () => void }[] — custom menu itemsappearance?: { buttonSize, buttonBg, menuBg, menuBorder } — stylingFeatures: Avatar with initials fallback, keyboard navigation (Arrow Up/Down, Escape), click-outside dismissal, accessible ARIA labels.
Complete login form with MFA support.
import { SignIn } from "@inai-dev/react";
<SignIn
redirectUrl="/dashboard"
onSuccess={() => console.log("Signed in!")}
onMFARequired={(mfaToken) => router.push("/mfa")}
/>
Props:
redirectUrl?: string — redirect on success (reloads page if omitted)onSuccess?: () => void — callback on successful sign-inonMFARequired?: (mfaToken: string) => void — callback if MFA neededTwo-step form: email/password → MFA code (if required). Unstyled HTML for easy customization.
Dropdown to switch between user's organizations.
import { OrganizationSwitcher } from "@inai-dev/react";
<OrganizationSwitcher />
Fetches orgs from /api/organizations, switches via POST /api/auth/set-active-organization, auto-reloads page after switch.
{
id: string
tenantId: string
email: string
firstName: string | null
lastName: string | null
avatarUrl: string | null
isActive: boolean
emailVerified: boolean
mfaEnabled: boolean
externalId: string | null
roles: string[]
createdAt: string
updatedAt: string
}
The React SDK expects these server-side routes to exist (created by @inai-dev/nextjs, @inai-dev/astro, @inai-dev/express, or @inai-dev/hono):
| Endpoint | Method | Used by |
|---|---|---|
/api/auth/login | POST | useSignIn(), <SignIn> |
/api/auth/register | POST | useSignUp() |
/api/auth/logout | POST | useAuth().signOut(), <UserButton> |
/api/auth/refresh | POST | useAuth().refreshSession() |
/api/auth/mfa-challenge | POST | useSignIn().attemptMFA(), <SignIn> |
/api/auth/set-active-organization | POST | <OrganizationSwitcher> |
/api/organizations | GET | <OrganizationSwitcher> |
When using React components inside Astro pages:
// src/components/AuthIsland.tsx
import { InAIAuthProvider, SignedIn, SignedOut, UserButton } from "@inai-dev/react";
export function AuthIsland() {
return (
<InAIAuthProvider>
<SignedIn>
<UserButton showName afterSignOutUrl="/login" />
</SignedIn>
<SignedOut>
<a href="/login">Sign in</a>
</SignedOut>
</InAIAuthProvider>
);
}
---
import { AuthIsland } from "../components/AuthIsland";
---
<AuthIsland client:load />
The provider reads one cookie on mount:
| Cookie | Purpose | httpOnly | Set by |
|---|---|---|---|
auth_session | User data + permissions (JSON) | No | Server-side auth routes |
The auth_session cookie contains:
{
user: UserResource
expiresAt: string
permissions: string[]
orgId?: string
orgRole?: string
appId?: string
envId?: string
}
When you need to check implementation details, the source files are at:
packages/react/src/context.tsx — InAIAuthProvider, context creationpackages/react/src/hooks/use-auth.ts — useAuth()packages/react/src/hooks/use-user.ts — useUser()packages/react/src/hooks/use-session.ts — useSession()packages/react/src/hooks/use-organization.ts — useOrganization()packages/react/src/hooks/use-sign-in.ts — useSignIn()packages/react/src/hooks/use-sign-up.ts — useSignUp()packages/react/src/components/protect.tsx — Protectpackages/react/src/components/signed-in.tsx — SignedInpackages/react/src/components/signed-out.tsx — SignedOutpackages/react/src/components/permission-gate.tsx — PermissionGatepackages/react/src/components/user-button.tsx — UserButtonpackages/react/src/components/sign-in.tsx — SignInpackages/react/src/components/org-switcher.tsx — OrganizationSwitchernpx claudepluginhub inai-team/inai-auth-skills --plugin inai-auth-skillsProvides React SPA auth patterns using @clerk/react for Vite/CRA: ClerkProvider setup, useAuth/useUser/useClerk hooks, React Router protected routes, custom sign-in flows.
Sets up Neon Auth in Next.js, React SPA, or Node.js apps. Configures auth routes, session management, social providers, and generates UI components.
Pre-built and custom Clerk authentication component templates with theming and customization patterns. Use when building authentication UI, creating sign-in/sign-up pages, customizing Clerk components, implementing user buttons, theming auth flows, or when user mentions Clerk components, SignIn, SignUp, UserButton, auth UI, appearance customization, or authentication theming.