Skip to main content

Overview

Auth0 is an enterprise identity platform that uses RS256 signing with JWKS for token verification. This guide shows you how to integrate Auth0 authentication with Revstack.

Prerequisites

  • An Auth0 account and tenant
  • An Auth0 API configured with an audience identifier
  • Auth0 access tokens being issued to your frontend application

Installation

npm install @revstackhq/auth

Configuration

1. Get your Auth0 credentials

From your Auth0 dashboard:
  1. Go to ApplicationsAPIs
  2. Select your API
  3. Note your Identifier (this is your audience)
  4. Note your Domain (e.g., your-tenant.us.auth0.com)

2. Build the auth contract

Create an auth contract using your Auth0 configuration:
import { buildAuthContract } from "@revstackhq/auth";

const authContract = buildAuthContract("auth0", {
  domain: "your-tenant.us.auth0.com", // With or without https://
  audience: "https://api.yourapp.com", // Your Auth0 API identifier
});
The contract builder automatically:
  • Normalizes the domain to HTTPS
  • Sets the JWKS URI to https://your-tenant.us.auth0.com/.well-known/jwks.json
  • Sets the issuer to https://your-tenant.us.auth0.com/
  • Configures RS256 verification strategy

Verification

Initialize the verifier

import { RevstackAuth } from "@revstackhq/auth";

const auth = new RevstackAuth(authContract);

Verify tokens

In your API routes or middleware:
export async function authMiddleware(req, res, next) {
  const session = await auth.validate(req.headers.authorization);

  if (!session.isValid) {
    return res.status(401).json({ error: session.error });
  }

  // Attach user info to request
  req.userId = session.userId; // Auth0 sub claim (e.g., "auth0|123456")
  req.claims = session.claims; // Full JWT payload
  
  next();
}

Token structure

Auth0 JWTs contain standard OIDC claims:
{
  "iss": "https://your-tenant.us.auth0.com/",
  "sub": "auth0|123456789",
  "aud": "https://api.yourapp.com",
  "iat": 1516239022,
  "exp": 1516242622,
  "azp": "your_client_id",
  "scope": "read:profile write:profile"
}

Custom claims

If you’ve added custom claims to your Auth0 tokens (via Actions/Rules), you can access them from session.claims:
interface Auth0Claims {
  "https://yourapp.com/roles": string[];
  "https://yourapp.com/plan": string;
}

const session = await auth.validate<Auth0Claims>(token);

if (session.isValid) {
  console.log(session.claims["https://yourapp.com/roles"]); // ["admin"]
  console.log(session.claims["https://yourapp.com/plan"]); // "pro"
}
Auth0 requires custom claims to be namespaced with a URL. Learn more in the Auth0 custom claims documentation.

Custom user ID claim

By default, Revstack uses the sub claim as the user ID. If you need to use a different claim:
const authContract = buildAuthContract("auth0", {
  domain: "your-tenant.us.auth0.com",
  audience: "https://api.yourapp.com",
  userIdClaim: "https://yourapp.com/user_id", // Custom claim
});

Complete example

Here’s a full Express.js integration:
import express from "express";
import { buildAuthContract, RevstackAuth, AuthErrorCode } from "@revstackhq/auth";

// Build contract once at startup
const authContract = buildAuthContract("auth0", {
  domain: process.env.AUTH0_DOMAIN!,
  audience: process.env.AUTH0_AUDIENCE!,
});

const auth = new RevstackAuth(authContract);

const app = express();

// Auth middleware
app.use(async (req, res, next) => {
  const authHeader = req.headers.authorization;
  
  if (!authHeader) {
    return res.status(401).json({ error: "Missing authorization header" });
  }

  const session = await auth.validate(authHeader);

  if (!session.isValid) {
    // Handle specific error cases
    if (session.errorCode === AuthErrorCode.TOKEN_EXPIRED) {
      return res.status(401).json({ 
        error: "Token expired",
        code: "token_expired" 
      });
    }
    
    return res.status(401).json({ error: session.error });
  }

  // Store user info on request
  req.userId = session.userId;
  req.claims = session.claims;
  
  next();
});

// Protected route
app.get("/api/profile", (req, res) => {
  res.json({
    userId: req.userId,
    scope: req.claims.scope,
  });
});

app.listen(3000);

Environment variables

Store your Auth0 configuration in environment variables:
# .env
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_AUDIENCE=https://api.yourapp.com

Testing

To test your integration:
  1. Obtain an access token from Auth0 (via your frontend app or Postman)
  2. Send it in the Authorization header: Bearer <token>
  3. Verify the token is validated correctly
You can also use Auth0’s test token generator for quick testing.

Troubleshooting

”Issuer mismatch” error

Ensure your Auth0 domain is correct and includes the trailing slash in the issuer. The contract builder handles this automatically.

”Invalid signature” error

Verify that:
  • The token was issued by the correct Auth0 tenant
  • The JWKS endpoint is accessible
  • The token hasn’t been tampered with

”Audience validation failed” error

Check that:
  • The audience parameter matches your Auth0 API identifier
  • Your Auth0 application is requesting the correct audience when obtaining tokens

Next steps

Auth Overview

Learn more about JWT verification in Revstack

Error Handling

Handle authentication errors gracefully

Build docs developers (and LLMs) love