TL;DR: Auth0 is the enterprise-grade auth provider (SAML, SSO, SCIM, custom rules). Create a tenant at auth0.com, create an Application, configure callback URLs, drop in their SDK, redirect. Pick over Clerk when you need IT-grade identity-provider plug-in.
Auth0 is the enterprise-grade auth provider β owned by Okta, used wherever SAML / SSO / SCIM matters. Heavier UI than Clerk; more rule customization; the right call when your auth requirements include "Fortune 500 IT can plug in their identity provider."
Auth0 is overkill for an indie SaaS. It's the right answer for B2B sold to IT departments.
Sign up at auth0.com/signup β. Free tier: 7,500 monthly active users for B2C, or 50 MAU for B2B with SSO enabled.
You're prompted to pick a tenant name and region. The tenant is the top-level container; everything else (Applications, Connections, Rules) lives under it. Most teams have one tenant per environment (dev, staging, prod).
Auth0 console β Applications β Create Application. Pick:
Click Create. You get a Domain, Client ID, and (for confidential apps) Client Secret.
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AUTH0_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # NEVER in browser
AUTH0_AUDIENCE=https://yourapp.com/api # for API auth (Step 8)
Application settings β scroll to Application URIs. Add:
http://localhost:3000/api/auth/callback, https://yourapp.com/api/auth/callbackhttp://localhost:3000, https://yourapp.comhttp://localhost:3000, https://yourapp.comExact match required. Trailing slash, http vs https, port number β all matter. Save.
Auth0 console β Authentication β Database for email/password. Or:
Authentication β Social for Google, GitHub, Apple, Microsoft, Facebook, etc. β toggle on; Auth0 provides default dev credentials, or paste your own from the provider's console (recommended for production).
Authentication β Enterprise for SAML, ADFS, Azure AD / Microsoft Entra ID, Google Workspace, Okta, OneLogin β the things your enterprise customers' IT departments will want to plug in.
npm install @auth0/nextjs-auth0
Add env vars (see Step 2). Create the API route:
// app/api/auth/[auth0]/route.ts
import { handleAuth } from '@auth0/nextjs-auth0';
export const GET = handleAuth();
Wrap your app:
// app/layout.tsx
import { UserProvider } from '@auth0/nextjs-auth0/client';
export default function RootLayout({ children }) {
return (
<html>
<body>
<UserProvider>{children}</UserProvider>
</body>
</html>
);
}
Other quickstarts: React, Vue, Angular, Express, Python, Java, .NET, iOS, Android β.
<a href="/api/auth/login">Sign in</a>
<a href="/api/auth/logout">Sign out</a>
Clicking Sign in redirects to Auth0's Universal Login page β the hosted sign-in UI. Users authenticate there; Auth0 redirects back to your app with the session cookie set.
Universal Login is customizable: console β Branding β Universal Login. Match colors, logo, copy. For deeper customization (your own UI), use the embedded login flow (more complex; embedded docs β).
// Server side (Next.js)
import { getSession } from '@auth0/nextjs-auth0';
export default async function Dashboard() {
const session = await getSession();
if (!session) redirect('/api/auth/login');
return <div>Hello {session.user.name}</div>;
}
// Client side
import { useUser } from '@auth0/nextjs-auth0/client';
export function Profile() {
const { user, isLoading } = useUser();
if (isLoading) return null;
if (!user) return <a href="/api/auth/login">Sign in</a>;
return <img src={user.picture} alt={user.name} />;
}
For separate backend APIs (not just app sessions), Auth0 issues signed JWTs your server validates.
Auth0 console β Applications β APIs β Create API. Set an Identifier (e.g., https://yourapp.com/api) β used as the JWT audience.
In your API:
npm install jose
import { jwtVerify, createRemoteJWKSet } from 'jose';
const JWKS = createRemoteJWKSet(new URL(
`https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`
));
export async function verifyAuth(req) {
const auth = req.headers.get('authorization');
if (!auth?.startsWith('Bearer ')) return null;
const token = auth.slice(7);
try {
const { payload } = await jwtVerify(token, JWKS, {
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
audience: process.env.AUTH0_AUDIENCE,
});
return payload; // contains sub (user ID), permissions, etc.
} catch {
return null;
}
}
JWKS rotation, signature verification β all handled by jose. JWT docs β.
Auth0's Actions run server-side JavaScript at key points in the auth flow β post-login, pre-registration, sending password change emails, etc. Use them for:
Auth0 console β Actions β Flows β Login β Add Action β Build Custom. Example:
exports.onExecutePostLogin = async (event, api) => {
// Add a custom claim to the token
api.idToken.setCustomClaim('https://yourapp.com/role', event.user.app_metadata?.role || 'member');
};
If your customers are companies (and each company has multiple users), use Organizations. Each org has its own connection settings, members, branding, and admin role.
Auth0 console β Organizations β Create Organization. Members sign in to a specific org via ?organization=org_xxx URL param.
This is one of Auth0's strongest B2B features β Clerk and Supabase Auth have similar concepts now, but Auth0's is deepest. Organizations docs β.
The reason most teams pick Auth0: enterprise SSO works out of the box.
Auth0 console β Authentication β Enterprise β SAML β Create Connection. Configure with the customer's IdP metadata. Tie it to an Organization. Users from that org now sign in via their company's IdP (Okta, Microsoft Entra ID, OneLogin, etc.).
SCIM provisioning (auto-creating/disabling users from the IdP) is also supported on Enterprise plans. SAML docs β Β· SCIM docs β.
By default users see your-tenant.auth0.com in the sign-in URL. For production, set up a custom domain (e.g., login.yourapp.com):
Auth0 console β Settings β Custom Domains β Add Domain. Add the required CNAME at your DNS provider. Wait for verification.
Requires Essentials plan or higher.
audience: AUTH0_AUDIENCE in the login call. Without it, you get an opaque token instead of a JWT, and your API can't validate it.