We use cookies to enhance your experience on the site
CodeWorlds
Back to collections
Guide12 min read

Auth0, authentication and identity management without your own backend

Auth0 provides login, SSO, MFA, and passkeys without your own backend. Current pricing, MAU limits, Next.js integration, and a Clerk comparison.

Auth0, authentication and identity management without your own backend

Auth0 takes over login, registration, password resets, two factor authentication, and connections to enterprise identity providers. Your application redirects the user to a login page and receives a token in return, which you verify. Since 2021 the product belongs to Okta, which strengthened its position in the enterprise segment and shaped its pricing.

When outsourcing login is worth it

Writing email and password login takes a day. The trouble starts afterwards: password resets, lockout after failed attempts, breached password detection, one time codes, Google sign in, then an enterprise customer asking for SAML, and finally a security audit.

It also pays to count what maintaining your own solution costs after launch. Not the day of work to build it, but reacting to change: a library update after a vulnerability report, a change in a social login provider's API, adjustments demanded by an audit, tickets about a broken password reset. That is several days a year nobody plans for, and they tend to land at the worst possible moment.

Auth0 starts paying off around the third item on that list. If your application has one login method and does not sell to companies, a homegrown implementation with a session library is often cheaper and simpler. If enterprise sales are on the roadmap, you buy login, because SAML and SCIM written in house are a quarter long project.

The second argument is liability. A password database on your own server is an obligation that weighs on every audit and every incident. Moving it to a vendor does not remove your duties around personal data, but it does remove the riskiest component.

Pricing and the user count trap

Billing rests on monthly active users, meaning accounts that logged in at least once. An account unused for a month does not count towards the limit.

PlanPriceMAU limitWhat you get
Free0 USDup to 25,000Password and social login, branded form, basic protections
Essentialsfrom 35 USD per month500Custom domain, basic roles, production features
Professionalfrom 240 USD per month500MFA, roles and permissions, SSO integrations, Actions
Enterprisecustom quotenegotiatedSLA, environment isolation, support

The table looks odd and it helps to know why. The free plan serves 25,000 users but without a custom domain, MFA, or roles. The paid plan starts at 500 users because you pay for features, not for scale. A team with five thousand users and an MFA requirement pays more than a team with twenty thousand users and no such requirement.

Billing above the threshold works in brackets rather than at a per user rate: exceeding the count included in a plan moves the whole bill into the next bracket. For an application with seasonal traffic spikes, price your peak month rather than the average, since one such month sets the bill at the higher level.

A second thing that is easy to miss when comparing offers is the separate track for products sold to companies. The same plans in the business variant cost several times more, with Essentials starting at a hundred and fifty dollars and Professional at eight hundred. If you are building a tool with organisation level sign in, look at that column from the start.

First integration

In Next.js the official library and four environment variables are enough.

Code
Bash
npm install @auth0/nextjs-auth0
Code
Bash
AUTH0_SECRET=generated_random_string
AUTH0_BASE_URL=http://localhost:3000
AUTH0_ISSUER_BASE_URL=https://your-domain.eu.auth0.com
AUTH0_CLIENT_ID=...
AUTH0_CLIENT_SECRET=...

You read the session on the server with one call, without threading a token through components.

TSapp/dashboard/page.tsx
TypeScript
// app/dashboard/page.tsx
import { getSession } from '@auth0/nextjs-auth0'
import { redirect } from 'next/navigation'

export default async function Dashboard() {
  const session = await getSession()
  if (!session) redirect('/api/auth/login')

  return <h1>Welcome, {session.user.name}</h1>
}

When deploying to Vercel, remember to change AUTH0_BASE_URL to the production address and to register the callback URLs in the Auth0 dashboard. Skipping that second step is the most common cause of a callback URL mismatch error on a first deployment.

Actions, or logic inside the login flow

Actions are JavaScript functions triggered at chosen moments: after credentials are verified, before a token is issued, after registration. That is where logic goes when configuration cannot express it.

Code
JavaScript
exports.onExecutePostLogin = async (event, api) => {
  const namespace = 'https://yourapplication.com'

  if (!event.user.email_verified) {
    api.access.deny('Confirm your email address before signing in.')
    return
  }

  api.idToken.setCustomClaim(`${namespace}/role`, event.user.app_metadata.role ?? 'user')
  api.accessToken.setCustomClaim(`${namespace}/organisation`, event.user.app_metadata.organisation)
}

Two things are worth knowing from the start. Custom token fields need a URL shaped prefix, because the OIDC standard forbids adding names without a namespace. Actions run on every login, so calling an external API inside one lengthens sign in for everybody.

Keep durable user attributes in app_metadata, since the user cannot change that field. The user_metadata field is editable by the user and is unfit for roles or permissions.

Passkeys and two factor authentication

Passkeys built on WebAuthn replace a password with device biometrics. For the user it is a fingerprint login, for the application it is phishing resistance, since the key is bound to the domain.

Adaptive MFA triggers a second factor conditionally: on a login from a new country, an unknown device, or at an unusual hour. That is a sensible compromise, because demanding a code on every login hurts conversion, while no second factor at all leaves accounts open after a password leak.

A rollout order that works in practice: breached password detection first, then MFA for administrative accounts, then adaptive MFA for everybody else, and passkeys last as an opt in. The reverse order produces support tickets and abandoned registrations.

Organisations, or multi tenancy in practice

An application sold to companies needs a concept of an organisation: a user belongs to one or several, holds a different role in each, and data stays separated. Auth0 ships this as Organizations, and using it beats building your own model.

Three practical consequences follow. The same email address can belong to two organisations, so the user identifier cannot be the email, it has to be the pair of account id and organisation id. Login can start with an organisation picker or with an address whose domain points at the right one. Invitations are handled by the platform, which saves building a bespoke flow with tokens in links.

The access token then carries an organisation identifier, and the API filters data on that basis. What matters is that filtering happens server side from the token, not from a parameter supplied by the client. A mistake here is the most serious class of bug in multi tenant applications, since it lets someone read another company's data by swapping one identifier in a request.

Keep the role model inside Auth0 only while it stays simple. For permissions tied to a resource, access to a specific project for instance, it makes more sense to hold them in your own database and put only organisation membership and a coarse role into the token.

Enterprise SSO step by step

A request to log in through the customer's own system usually surfaces during negotiations rather than in a quarterly plan. It helps to know in advance what it entails.

The customer hands over metadata for their identity provider, most often as an XML URL or a file. You configure the connection in Auth0, make it available to that customer's organisation, and map attributes, deciding which field in their directory is a first name and which an email address.

The biggest surprise usually concerns groups. The customer sends a list of directory groups under their own naming scheme and expects them to translate into roles in your application. You build that mapping in Actions, and agreeing its shape before signing the contract pays off, because per customer rules grow faster than the team does.

The second matter is disabling password login for users from the customer's domain. A company rolling out SSO normally requires that access without their system stops working, including for accounts created earlier.

Auth0 against the alternatives

SolutionStrengthWeaknessPick it when
Auth0Mature enterprise SSO, SAML, deep extensibilityPricing jumps once you need MFA and rolesEnterprise sales, compliance requirements
ClerkReady made UI components, fast start in ReactFewer enterprise optionsSaaS for individuals and small teams
Supabase AuthIncluded with the database, full control over dataFewer prebuilt SSO integrationsProject already built on Supabase
KindeSimple pricing, generous free thresholdYounger product, smaller communityStartup watching costs
HomegrownNo external cost, full controlThe entire security burden is yoursOne login method, no enterprise requirements

The decision is rarely reversible without cost, because migrating identities between vendors means moving passwords that are hashed. Auth0 can import hashes in common formats, but not every vendor exports them. Check the export terms before choosing a platform.

Security that stays your responsibility

Auth0 secures the login flow, but verifying the token is your application's job. Three mistakes recur most often.

The first is checking only the signature without validating the aud and iss claims. A token issued for a different application in the same tenant passes that check.

The second is keeping an access token in localStorage. A script injected into the page reads it without obstacle. A cookie with the HttpOnly and Secure flags is safer, and with server side rendering also more convenient.

The third is making authorisation decisions from the identity token instead of the access token. The first describes who the user is, the second states what they may do in a specific API.

The fourth concerns token lifetimes. Defaults tend to be too generous for an application handling financial data and too strict for a tool used all day. A short access token paired with a longer refresh token under rotation reconciles convenience with the ability to cut a session once abuse is detected. Without rotation, a stolen refresh token works until it expires and there is no way to revoke it individually.

Separately, set up signing key rotation and confirm that your application library fetches keys dynamically from the JWKS endpoint rather than having them hardcoded.

Common deployment mistakes

The first is having no test environment. A separate tenant for staging costs nothing and lets you test Action changes without risking a production lockout.

The second is configuration clicked in the dashboard with nothing recorded in the repository. A year later nobody remembers why a given rule exists. Configuration can be exported and versioned with the command line tool.

The third is serving users worldwide without setting the tenant region. Redirecting to a server on the other side of an ocean adds hundreds of milliseconds to every login.

The fourth is having no plan for vendor downtime. Login stops working for everyone at once, so decide in advance what you tell users and whether sessions already open survive the outage. A longer session lifetime means signed in users never notice a short interruption.

The fifth is ignoring management API rate limits. A nightly user synchronisation script can exhaust the quota and back off with an error, leaving some accounts out of sync with no alarm raised.

FAQ

What does Auth0 cost at a thousand users?

It depends on the features you need, not on the count itself. A thousand users fit inside the free plan if password and social login suffice. Requiring MFA, roles, or SSO integrations moves the project to the Professional plan from 240 USD per month.

Can I migrate users from my own database?

Yes, in two ways. Importing password hashes works when you use a supported algorithm such as bcrypt. The alternative is gradual migration, where Auth0 queries your old database on first login and moves the account across after a successful authentication.

How does Auth0 differ from Clerk?

Auth0 targets enterprise scenarios: SAML, corporate directories, elaborate rules. Clerk bets on ready made UI components and quick adoption in a React application. For sales to large companies Auth0 usually wins, for a consumer facing product Clerk more often does.

Does Auth0 work without redirecting to a login page?

You can build your own form and post credentials through the API, but you then lose part of the protection built into Universal Login, including credential stuffing defence and bot detection. The recommended route is a login page carrying your own styling and domain.

What happens when the MAU limit is exceeded?

The service keeps working and the bill moves into a higher pricing bracket, since the vendor does not meter overage per individual user. It is worth setting an alert at 80 percent of the limit, because the threshold gets crossed without warning during a traffic spike, and the result is a jump in the bill rather than a gradual rise.

Current pricing sits on auth0.com, and the documentation at auth0.com/docs.