From inai-auth-skills
Integrate InAI Auth SDK into Next.js applications. Use this skill whenever the user wants to add authentication, login, signup, middleware protection, role-based access control (RBAC), MFA, or session management to a Next.js app using @inai-dev/nextjs. Also trigger when the user mentions InAI auth with Next.js, asks about protecting routes in Next.js, needs auth hooks (useAuth, useUser), wants to set up auth API routes, or is building an admin panel that needs platform authentication. Covers both app user auth and platform/admin auth flows.
How this skill is triggered — by the user, by Claude, or both
Slash command
/inai-auth-skills:inai-nextjs-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 Next.js 14+ applications using the `@inai-dev/nextjs` package.
This skill guides you through integrating InAI Auth into Next.js 14+ applications using the @inai-dev/nextjs package.
https://apiauth.inai.dev — hardcoded in the SDK, never configurableINAI_PUBLISHABLE_KEY=pk_live_...@inai-dev/nextjs (depends on @inai-dev/react and @inai-dev/backend)"app" (end users) and "platform" (admin/developer panels)npm install @inai-dev/nextjs
<InAIAuthProvider> in root layoutapp/api/auth/[...inai]/route.tsmiddleware.ts at project rootauth(), currentUser() in server components/actions// app/layout.tsx
import { InAIAuthProvider } from "@inai-dev/nextjs";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<InAIAuthProvider>
{children}
</InAIAuthProvider>
</body>
</html>
);
}
The provider reads the auth_session cookie on mount to hydrate client-side state.
// app/api/auth/[...inai]/route.ts
import { createAuthRoutes } from "@inai-dev/nextjs/server";
const { GET, POST } = createAuthRoutes();
export { GET, POST };
Creates these endpoints automatically:
POST /api/auth/login — Login, sets httpOnly cookiesPOST /api/auth/register — RegistrationPOST /api/auth/mfa-challenge — TOTP MFA verificationPOST /api/auth/refresh — Token rotationPOST /api/auth/logout — Invalidate session, clear cookies// app/api/auth/[...inai]/route.ts
import { createPlatformAuthRoutes } from "@inai-dev/nextjs/server";
const { GET, POST } = createPlatformAuthRoutes();
export { GET, POST };
Uses /api/platform/auth/* endpoints. No publishable key needed for platform auth.
// middleware.ts
import { inaiAuthMiddleware } from "@inai-dev/nextjs/middleware";
export default inaiAuthMiddleware({
publicRoutes: ["/", "/about", "/pricing", "/login", "/register"],
signInUrl: "/login",
// jwksUrl: "https://apiauth.inai.dev/.well-known/jwks.json", // optional override
});
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
/_next/*, /favicon.ico, /api/*, signInUrl) pass throughpublicRoutes pass throughauth_token JWT signature using ES256 via JWKS (cached 5 min, auto-retry on key rotation)refresh_token → auto-refresh via /api/auth/refreshsignInUrl with returnTo parampublicRoutes: (req) => req.nextUrl.pathname.startsWith("/public/")
export default inaiAuthMiddleware({
publicRoutes: ["/"],
signInUrl: "/login",
beforeAuth: (req) => {
// Return NextResponse to short-circuit
},
afterAuth: (auth, req) => {
// Role-based routing
if (req.nextUrl.pathname.startsWith("/admin") && !auth.has({ role: "admin" })) {
return NextResponse.redirect(new URL("/unauthorized", req.url));
}
},
});
import { inaiAuthMiddleware, createRouteMatcher } from "@inai-dev/nextjs/middleware";
const isAdminRoute = createRouteMatcher(["/admin(.*)"]);
export default inaiAuthMiddleware({
publicRoutes: ["/", "/login"],
afterAuth: (auth, req) => {
if (isAdminRoute(req) && !auth.has({ role: "admin" })) {
return NextResponse.redirect(new URL("/", req.url));
}
},
});
import { withInAIAuth } from "@inai-dev/nextjs/middleware";
import createIntlMiddleware from "next-intl/middleware";
const intlMiddleware = createIntlMiddleware({ locales: ["en", "es"], defaultLocale: "en" });
export default withInAIAuth(intlMiddleware, {
publicRoutes: ["/", "/login"],
signInUrl: "/login",
});
// Server Component
import { auth } from "@inai-dev/nextjs/server";
export default async function Page() {
const { userId, has, protect, redirectToSignIn } = await auth();
// Option 1: Manual check
if (!userId) redirectToSignIn({ returnTo: "/dashboard" });
// Option 2: protect() — redirects if not authenticated/authorized
const { userId: uid } = protect({ role: "admin" });
// Option 3: Conditional rendering
const canEdit = has({ permission: "content:write" });
return <div>{canEdit && <EditButton />}</div>;
}
import { currentUser } from "@inai-dev/nextjs/server";
// From session cookie (fast, no network)
const user = await currentUser();
// Fresh from API
const freshUser = await currentUser({ fresh: true });
import { configureAuth } from "@inai-dev/nextjs/server";
configureAuth({
signInUrl: "/sign-in",
signUpUrl: "/sign-up",
afterSignInUrl: "/dashboard",
afterSignOutUrl: "/sign-in",
publishableKey: process.env.INAI_PUBLISHABLE_KEY,
});
| Hook | Returns |
|---|---|
useAuth() | isLoaded, isSignedIn, userId, roles, permissions, has(), signOut() |
useUser() | isLoaded, isSignedIn, user (full UserResource) |
useSession() | isLoaded, isSignedIn, userId, tenantId, orgId, orgRole, roles, permissions |
useOrganization() | isLoaded, orgId, orgRole |
| Component | Purpose |
|---|---|
<SignIn> | Complete login form with MFA support |
<UserButton> | Avatar dropdown with user info and sign-out |
<SignedIn> | Render children only when authenticated |
<SignedOut> | Render children only when unauthenticated |
<Protect> | Render children if user has required role/permission |
<PermissionGate> | Role/permission gating |
<OrganizationSwitcher> | Org selector dropdown |
"use client";
import { SignedIn, SignedOut, UserButton } from "@inai-dev/nextjs";
export function Navbar() {
return (
<nav>
<SignedIn>
<UserButton showName afterSignOutUrl="/login" />
</SignedIn>
<SignedOut>
<a href="/login">Sign in</a>
</SignedOut>
</nav>
);
}
| Cookie | Purpose | httpOnly | Path | MaxAge |
|---|---|---|---|---|
auth_token | Access JWT | Yes | / | Token expiry |
refresh_token | Refresh JWT | Yes | / | 7 days |
auth_session | User data (readable by JS) | No | / | Token expiry |
The auth_session cookie is what the InAIAuthProvider reads on mount to hydrate client state without a network request.
"use server";
import { auth } from "@inai-dev/nextjs/server";
export async function updateProfile(formData: FormData) {
const { protect } = await auth();
protect(); // userId guaranteed non-null after this
// ... update logic
}
Both server and client auth objects share this structure:
{
userId: string | null
tenantId: string | null
appId: string | null
envId: string | null
orgId: string | null
orgRole: string | null
sessionId: string | null
roles: string[]
permissions: string[]
getToken(): Promise<string | null>
has(params: { role?: string; permission?: string }): boolean
}
Server-only additions: protect(), redirectToSignIn().
const res = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
const data = await res.json();
if (data.mfa_required) {
// Show MFA input, then submit:
await fetch("/api/auth/mfa-challenge", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ mfa_token: data.mfa_token, code: totpCode }),
});
}
// Redirect to dashboard
import { auth } from "@inai-dev/nextjs/server";
export default async function AdminPage() {
const { protect } = await auth();
protect({ role: "admin", redirectTo: "/unauthorized" });
return <AdminDashboard />;
}
When you need to check implementation details, the source files are at:
packages/nextjs/src/middleware.ts — Middleware implementationpackages/nextjs/src/server.ts — auth(), currentUser(), configureAuth()packages/nextjs/src/api-routes.ts — createAuthRoutes()packages/nextjs/src/platform-api-routes.ts — createPlatformAuthRoutes()packages/nextjs/src/config.ts — Configuration managementpackages/nextjs/src/cookies.ts — Cookie utilitiespackages/react/src/context.tsx — InAIAuthProviderpackages/react/src/hooks/ — All React hookspackages/react/src/components/ — Pre-built componentspackages/shared/src/jwks.ts — JWKSClient (JWKS key fetching, caching, error throttling)packages/shared/src/jwt.ts — ES256 verification, JWT decodingnpx claudepluginhub inai-team/inai-auth-skills --plugin inai-auth-skillsImplements complete Next.js authentication with Auth.js: OAuth providers (GitHub/Google), credentials login, Prisma adapter, session management (JWT/DB), middleware-protected routes, RBAC, and login forms.
Implements Next.js authentication with NextAuth.js v5, middleware for protected routes, server/client session access, and JWT strategies.
Implements authentication in Next.js using Auth.js v5 with session handling, middleware guards, server-side session access, and OAuth integration.