Auth0’s Authentication API isn’t just a way to log users in; it’s a highly configurable gateway that can rewrite user attributes, enforce complex authorization rules, and even federate identities from dozens of external providers before your application ever sees the user.

Let’s see it in action. Imagine we have a simple Node.js app and we want to authenticate users using their Google account.

// server.js
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const auth0Strategy = require('passport-auth0'); // We'll use this one

const app = express();

// Session configuration
app.use(session({
  secret: 'your-very-secret-key', // In production, use a strong, environment-variable-based secret
  resave: false,
  saveUninitialized: true
}));

// Passport initialization
app.use(passport.initialize());
app.use(passport.session());

// Auth0 strategy configuration
passport.use(new auth0Strategy({
    domain: 'YOUR_AUTH0_DOMAIN.auth0.com', // Replace with your Auth0 domain
    clientID: 'YOUR_AUTH0_CLIENT_ID',     // Replace with your Auth0 Client ID
    clientSecret: 'YOUR_AUTH0_CLIENT_SECRET', // Replace with your Auth0 Client Secret
    callbackURL: 'http://localhost:3000/callback' // Replace with your callback URL
  },
  (accessToken, refreshToken, extraParams, profile, done) => {
    // This is where Auth0 returns user info after successful authentication
    // 'profile' contains information from Auth0, including user ID and custom properties
    return done(null, profile);
  }
));

// Serialize and deserialize user for session management
passport.serializeUser((user, done) => {
  done(null, user);
});

passport.deserializeUser((user, done) => {
  done(null, user);
});

// Routes
app.get('/', (req, res) => {
  res.send(req.isAuthenticated() ? `Hello, ${req.user.displayName}! <a href="/logout">Logout</a>` : '<a href="/login">Login with Auth0</a>');
});

app.get('/login', passport.authenticate('auth0', { scope: 'openid email profile' }));

app.get('/callback', passport.authenticate('auth0', { failureRedirect: '/' }), (req, res) => {
  res.redirect('/');
});

app.get('/logout', (req, res) => {
  req.logout();
  res.redirect('/');
});

const port = 3000;
app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
});

To get this running:

  1. Create an Auth0 Application: Go to your Auth0 dashboard, create a new application, and select "Regular Web Application."
  2. Configure Callback URLs: In your Auth0 application’s settings, under "Application URIs," add http://localhost:3000/callback to the "Allowed Callback URLs."
  3. Install Dependencies:
    npm install express express-session passport passport-auth0
    
  4. Replace Placeholders: Update YOUR_AUTH0_DOMAIN, YOUR_AUTH0_CLIENT_ID, and YOUR_AUTH0_CLIENT_SECRET in the code with your actual Auth0 credentials.
  5. Run the Server: node server.js

Now, when you visit http://localhost:3000, you’ll see a "Login with Auth0" link. Clicking it redirects you to Auth0’s hosted login page. After you successfully log in with a Google account (or any social provider you’ve configured in Auth0), Auth0 handles the verification and redirects you back to your application’s /callback endpoint. Passport then uses the accessToken and profile information from Auth0 to establish a session for your user.

The real power here is that Auth0 is doing the heavy lifting of communicating with Google, verifying credentials, and providing a standardized profile object to your application. Your Node.js app doesn’t need to know the intricacies of the Google OAuth 2.0 flow; it just trusts Auth0.

Internally, when your user clicks /login, Passport instructs Auth0 to initiate an OAuth 2.0 Authorization Code Grant flow. Auth0 presents its login page, allowing the user to choose their identity provider (like Google). Once authenticated with Google, Auth0 receives the user’s information, performs any configured actions (like attribute transformations or custom database lookups), and then generates its own ID Token and Access Token for your application. The /callback endpoint receives an authorization code, which your backend exchanges with Auth0 for these tokens. The profile object you receive in the Passport strategy callback is derived from the ID Token and user information retrieved by Auth0.

You control the user experience and the identity providers available through Auth0’s dashboard. You can enable/disable social connections, configure enterprise connections (SAML, AD/LDAP), and set up passwordless authentication. Crucially, you can use Auth0’s Rules and Actions to intercept the authentication flow after the user has successfully authenticated with their provider but before they are redirected back to your application. This is where you can add custom logic:

  • Enrich User Profiles: Fetch data from your own database based on the user’s email and add it to the profile object returned by Auth0. For instance, you could add a user.roles array.
  • Enforce Policies: Check if a user belongs to a specific group or has a certain attribute, and deny access or redirect them elsewhere if they don’t meet the criteria.
  • Token Customization: Add custom claims to the ID Token or Access Token that your application can then use for authorization decisions.

The scope parameter in passport.authenticate('auth0', { scope: 'openid email profile' }) is a direct mapping to OpenID Connect scopes. openid is mandatory for authentication. email requests the user’s email address, and profile requests basic profile information like name and picture. Auth0 supports a wide range of scopes, allowing you to request specific claims about the user.

The profile object passed to done in the strategy callback contains a wealth of information, but its exact structure depends on the identity provider and the scopes requested. For Google, it typically includes id, displayName, name.givenName, name.familyName, emails, and photos. Auth0 can also inject custom properties here via Rules/Actions.

The underlying mechanism Auth0 uses to manage user sessions for your application involves issuing JSON Web Tokens (JWTs). When a user logs in, Auth0 generates an ID Token (containing user identity information) and an Access Token (for authorizing API calls). Your application validates these tokens, often using libraries like express-jwt or Passport’s built-in JWT strategy, to ensure the user is authenticated and authorized. The accessToken and refreshToken in the strategy callback are Auth0’s tokens, which you can use for further API interactions on behalf of the user.

The most surprising thing about Auth0’s Authentication API is how much logic it can encapsulate away from your application code. You can delegate complex identity management, multi-factor authentication, and even federated identity brokering to Auth0, keeping your application focused solely on its core business logic. This separation of concerns dramatically simplifies your backend and improves security by centralizing authentication handling.

The next step after integrating basic social login is often implementing authorization checks based on the enriched user profile or custom token claims.

Want structured learning?

Take the full Auth0 course →