Quickstart

Next.js

Sign-in in five minutes with @authio/nextjs and @authio/react.

This guide ends with a Next.js 15 app where sign-in works against your Authio project. We assume you already have a project and an sk_live_ key — if not, see Provisioning a project.

1. Install

pnpm add @authio/nextjs @authio/react

2. Configure environment

Add the following to .env.local. The publishable key is safe to expose to the browser; the secret key stays server-side.

AUTHIO_PUBLISHABLE_KEY=pk_live_...
AUTHIO_SECRET_KEY=sk_live_...
NEXT_PUBLIC_AUTHIO_API_URL=https://api.authio.com

3. Add the middleware

Drop this in middleware.ts at your project root. It verifies the Authio session JWT against the cached JWKS at the edge, with no round-trip to auth-core.

// middleware.ts
import { authMiddleware } from "@authio/nextjs";

export default authMiddleware({
  apiUrl: process.env.NEXT_PUBLIC_AUTHIO_API_URL,
  publicRoutes: ["/", "/pricing", "/sign-in"],
});

export const config = {
  matcher: ["/((?!_next|.*\\..*).*)"],
};

4. Wrap the app in AuthioProvider

// app/layout.tsx
import { AuthioProvider } from "@authio/react";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <AuthioProvider
          publishableKey={process.env.NEXT_PUBLIC_AUTHIO_PUBLISHABLE_KEY!}
          apiUrl={process.env.NEXT_PUBLIC_AUTHIO_API_URL}
        >
          {children}
        </AuthioProvider>
      </body>
    </html>
  );
}

5. Drop in the sign-in surface

// app/sign-in/page.tsx
import { SignIn } from "@authio/react";

export default function SignInPage() {
  return <SignIn redirectAfter="/dashboard" />;
}

6. Read the session in a Server Component

// app/dashboard/page.tsx
import { auth } from "@authio/nextjs/server";

export default async function DashboardPage() {
  const { userId, orgId, role } = await auth();
  if (!userId) {
    return <p>Please sign in.</p>;
  }
  return (
    <div>
      <p>User {userId}</p>
      <p>Active organization {orgId ?? "(none selected)"}</p>
      <p>Role {role ?? "n/a"}</p>
    </div>
  );
}
Multi-org tip. If orgId is null after sign-in, the user has multiple memberships and hasn’t picked one yet. Render an <OrganizationSwitcher /> from @authio/react to let them choose — switching is a no-re-auth call to POST /v1/sessions/switch-org.

What you just did

Your Next.js app now verifies real Authio JWTs at the Edge runtime using cached JWKS, exposes a typed auth() helper to Server Components, and renders the Authio-hosted login experience with one component. From here, see One user, many orgs for the multi-org session model.