Webrizendocs
Integrate your app

Next.js SDK

@webrizen/sso adds "Sign in with Webrizen" to a Next.js App Router app: login, callback, logout, encrypted sessions and permission checks. It's built on the certified openid-client library.

Install

The SDK lives in this monorepo at packages/sdk. Inside the monorepo, depend on it with workspace:*. For separate repositories, publish it to npm (public or private) or install it from Git.

pnpm add @webrizen/sso

Setup

Register the app

In Webrizen SSO go to Platform → Applications → Register application with the redirect URI https://your-app.com/api/auth/webrizen/callback. Copy the client ID and secret.

Add environment variables

.env.local
APP_URL=https://restaurant.webrizen.com
WEBRIZEN_SSO_ISSUER=https://accounts.webrizen.com/api/auth
WEBRIZEN_SSO_CLIENT_ID=…
WEBRIZEN_SSO_CLIENT_SECRET=…
WEBRIZEN_SSO_SESSION_SECRET=… # 32+ random characters, e.g. openssl rand -base64 32

Create the client

lib/webrizen.ts
import { createWebrizenAuth, fromEnv } from "@webrizen/sso/next";
 
export const webrizen = createWebrizenAuth(fromEnv());

Mount the route handler

app/api/auth/webrizen/[action]/route.ts
import { webrizen } from "@/lib/webrizen";
 
export const GET = webrizen.handler;

That one file serves /login, /callback, /logout and /refresh.

Use the session

app/dashboard/page.tsx
import { can } from "@webrizen/sso";
import { webrizen } from "@/lib/webrizen";
 
export default async function Dashboard() {
  const session = await webrizen.requireSession("/dashboard");
 
  return (
    <>
      <h1>Hello {session.user.name}</h1>
      <p>{session.org?.name} · {session.org?.roles.join(", ")}</p>
      {can(session, "order", "refund") && <RefundButton />}
    </>
  );
}

Routes

LinkWhat it does
/api/auth/webrizen/loginStarts sign-in. Add ?returnTo=/path to come back somewhere specific
/api/auth/webrizen/login?prompt=select_accountRe-runs sign-in so the user can pick a different organization
/api/auth/webrizen/login?prompt=createOpens the sign-up page instead of sign-in
/api/auth/webrizen/refreshUses the refresh token to reload roles and permissions
/api/auth/webrizen/logoutSigns out of the app and Webrizen SSO
/api/auth/webrizen/logout?global=falseSigns out of this app only

API

createWebrizenAuth(config) → {
  handler,                          // route handler for [action]
  getSession(): Promise<WebrizenSession | null>,
  requireSession(returnTo?): Promise<WebrizenSession>, // redirects to login if signed out
}
 
can(session, resource, action): boolean
hasRole(session, role): boolean
type WebrizenSession = {
  user: { id: string; email: string; emailVerified: boolean; name: string; image: string | null };
  org: {
    id: string; name: string; slug: string; logo: string | null;
    roles: string[];
    teams: { id: string; name: string }[];
    permissions: Record<string, string[]>;
  } | null;
  accessToken: string;
  refreshToken?: string;
  idToken?: string;
  expiresAt: number; // unix seconds, access token expiry
};

How sessions work

  • The session is stored in an encrypted, HTTP-only cookie (A256GCM, key derived from WEBRIZEN_SSO_SESSION_SECRET). No database is needed in your app.
  • Default lifetime is 7 days (sessionMaxAge to change it).
  • Roles and permissions are captured at sign-in. Link to /api/auth/webrizen/refresh after an admin changes someone's role, or let them sign in again.

Configuration

fromEnv() reads the variables above. For full control, pass a config object:

createWebrizenAuth({
  issuer: "https://accounts.webrizen.com/api/auth",
  clientId: "…",
  clientSecret: "…",
  redirectUri: "https://restaurant.webrizen.com/api/auth/webrizen/callback",
  postLogoutRedirectUri: "https://restaurant.webrizen.com",
  sessionSecret: process.env.SESSION_SECRET!,
  sessionMaxAge: 60 * 60 * 12, // 12 hours
  scopes: ["openid", "profile", "email", "organization", "offline_access"],
  cookieName: "restaurant_session",
});
Protect whole sections with Proxy

For many protected routes, check for the session cookie in proxy.ts and redirect to /api/auth/webrizen/login?returnTo=…. Then call requireSession() in pages for the real check.