express-openid-connect vs oidc-provider
Implementing OpenID Connect Authentication in Node.js
express-openid-connectoidc-provider

Implementing OpenID Connect Authentication in Node.js

express-openid-connect and oidc-provider are both essential libraries for working with OpenID Connect (OIDC) in Node.js, but they serve opposite ends of the authentication flow. express-openid-connect acts as a client (Relying Party) that integrates login functionality into an existing web application using an external identity provider. oidc-provider acts as a server (OpenID Provider) that issues tokens and manages user identities, effectively allowing you to build your own authentication service like Auth0 or Okta.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
express-openid-connect0512117 kB232 days agoMIT
oidc-provider03,707614 kB010 days agoMIT

express-openid-connect vs oidc-provider: Client vs Server Architecture

Both express-openid-connect and oidc-provider are mature libraries for handling OpenID Connect (OIDC) in Node.js environments, but they solve fundamentally different problems. One is designed to consume authentication, while the other is designed to provide it. Understanding this distinction is critical for architecting secure systems.

🎯 Core Role: Consuming Auth vs Issuing Auth

express-openid-connect acts as a Relying Party (RP).

  • It connects your app to an external Identity Provider (IdP).
  • You use this when you want users to log in via Auth0, Google, or your own OIDC server.
// express-openid-connect: Configuring the client
const { auth } = require('express-openid-connect');

app.use(auth({
  auth0: {
    domain: 'your-tenant.auth0.com',
    clientId: 'your-client-id'
  },
  baseURL: 'http://localhost:3000',
  secret: 'long-secret-string'
}));

oidc-provider acts as an OpenID Provider (OP).

  • It is the server that validates credentials and issues tokens.
  • You use this when you are building the service that other apps log in to.
// oidc-provider: Configuring the server
const Provider = require('oidc-provider');

const provider = new Provider('http://localhost:3000', {
  findAccount: async (ctx, id) => {
    // Logic to find user in your database
    return { accountId: id };
  },
  scopes: ['openid', 'profile', 'email']
});

app.use(provider.callback);

βš™οΈ Configuration Complexity: Opinionated vs Flexible

express-openid-connect favors convention over configuration.

  • It comes with sensible defaults for security settings like PKCE and token validation.
  • Setup is fast, but you have less control over the underlying protocol flow.
// express-openid-connect: Minimal setup
app.use(auth({
  issuerBaseURL: 'https://your-idp.com',
  baseURL: 'https://your-app.com',
  clientID: 'client-id',
  secret: 'secret'
}));
// Routes are protected automatically with authRequired

oidc-provider requires explicit definition of almost every behavior.

  • You must define how interactions (login screens) work.
  • You must configure token lifetimes, CORS, and cookie settings manually.
// oidc-provider: Explicit interaction policy
const policy = Provider.interactionPolicy.base();
policy.add(new Provider.interactionPolicy.Prompt({
  name: 'login',
  requestable: true
}));

const provider = new Provider('http://localhost:3000', {
  interactions: { policy }
});

πŸ”’ Protecting Routes vs Handling Requests

express-openid-connect provides middleware to guard your routes.

  • You wrap specific routes to ensure a user is logged in.
  • It automatically handles redirects to the IdP and back.
// express-openid-connect: Protecting a route
app.get('/dashboard', authRequired, (req, res) => {
  res.send(`Hello ${req.oidc.user.name}`);
});

app.get('/login', (req, res) => {
  res.oidc.login({ returnTo: '/dashboard' });
});

oidc-provider mounts to your app to handle incoming auth requests.

  • It listens for authorization and token endpoint calls.
  • You build the UI that captures the username and password.
// oidc-provider: Mounting the provider
// In your Express app
app.use('/oidc', provider.callback);

// You still need to build your own login form UI
app.get('/login', (req, res) => {
  res.send('<form>...</form>'); // Custom UI implementation
});

πŸͺ Session Management: Built-in vs Custom

express-openid-connect manages the user session for your app.

  • It creates an encrypted cookie session after login.
  • You access user data via req.oidc.user without extra code.
// express-openid-connect: Accessing session
app.get('/profile', authRequired, (req, res) => {
  // Session is automatically populated
  const user = req.oidc.user;
  res.json(user);
});

oidc-provider expects you to manage sessions for the Identity Server.

  • It does not log users into your main app; it logs them into the IdP.
  • You must implement findAccount and session persistence logic.
// oidc-provider: Implementing account lookup
const config = {
  findAccount: async (ctx, id, token) => {
    // You must fetch from your DB
    const user = await db.users.findById(id);
    return {
      accountId: user.id,
      claims: () => ({ sub: user.id, name: user.name })
    };
  }
};

🀝 Similarities: Shared Ground Between Client and Server

While their roles differ, both libraries share underlying standards and dependencies.

1. πŸ” Both Rely on OpenID Connect Standards

  • Implement core OIDC flows (Authorization Code, Implicit, Hybrid).
  • Support standard scopes like openid, profile, and email.
// Both support standard scopes
// express-openid-connect config
{ scopes: ['openid', 'profile'] }

// oidc-provider config
{ scopes: ['openid', 'profile'] }

2. πŸš€ Both Run on Express/Node.js

  • Designed as Express middleware or compatible modules.
  • Fit into standard Node.js HTTP server architectures.
// Both integrate with Express
const express = require('express');
const app = express();

// Works with either package
app.use(express.json());

3. πŸ›‘οΈ Both Prioritize Security Best Practices

  • Enforce HTTPS in production modes.
  • Support secure cookie flags and token encryption.
// express-openid-connect: Secure cookies
{ session: { cookie: { secure: true } } }

// oidc-provider: Secure cookies
{ cookies: { secure: true } }

4. πŸ”§ Both Allow Custom Claims

  • You can add extra user data to tokens.
  • Useful for roles, permissions, or tenant IDs.
// express-openid-connect: After login hook
{ afterCallback: (req, res, session, state) => {
    session.myCustomClaim = 'value';
}}

// oidc-provider: Extra claims
{ claims: { extra: ['myCustomClaim'] } }

5. πŸ“¦ Both Are Actively Maintained

  • Regular updates for security patches.
  • Strong documentation and community support.
// Both follow semantic versioning
// Check package.json for latest versions

πŸ“Š Summary: Key Similarities

FeatureShared by Both
ProtocolπŸ” OpenID Connect & OAuth 2.0
RuntimeπŸš€ Node.js & Express
SecurityπŸ›‘οΈ HTTPS & Encryption support
ExtensibilityπŸ”§ Custom claims & hooks
MaintenanceπŸ“¦ Active community support

πŸ†š Summary: Key Differences

Featureexpress-openid-connectoidc-provider
RoleπŸ§‘β€πŸ’» Client (Relying Party)🏒 Server (Identity Provider)
Setup Time⚑ Minutes (Hosted IdP)🐒 Days/Weeks (Self-hosted)
User Storage🚫 External (Auth0, etc.)πŸ’Ύ Your Database
UI Control🎨 Hosted Login PagesπŸ–ŒοΈ Fully Custom Login UI
Responsibilityβœ… Low (Vendor manages security)⚠️ High (You manage security)

πŸ’‘ The Big Picture

express-openid-connect is like renting a secure apartment πŸ’β€”everything is maintained for you, and you just move in. Ideal for startups, SaaS products, and teams that want to ship features without becoming security experts.

oidc-provider is like building your own house from the ground up πŸ—οΈβ€”you control every brick, but you are responsible for the roof not leaking. Best for enterprises with strict compliance needs, legacy user databases, or those building an identity platform as a product.

Final Thought: Do not build your own identity server unless you have to. Start with express-openid-connect and a managed provider. Only reach for oidc-provider when business requirements demand full ownership of the authentication flow.

How to Choose: express-openid-connect vs oidc-provider

  • express-openid-connect:

    Choose express-openid-connect if you are building a standard web application and need to add user login quickly using an existing identity provider like Auth0, Okta, or Azure AD. It handles the complex OIDC callback exchanges and session management for you, letting you focus on your app's features rather than security protocols. This is the ideal starting point for most teams who do not need to manage user credentials directly.

  • oidc-provider:

    Choose oidc-provider if you need to build your own identity server to issue tokens for multiple applications or devices. It is the right choice when you require full control over user storage, login UI, token issuance rules, and compliance with specific OIDC certification requirements. Use this only if you have the security expertise to maintain an authentication server, as it shifts the burden of safety onto your team.

README for express-openid-connect

Express JS middleware implementing sign on for Express web apps using OpenID Connect.

Release Codecov Ask DeepWiki Downloads License CircleCI

πŸ“š Documentation - πŸš€ Getting Started - πŸ’» API Reference - πŸ’¬ Feedback

Documentation

  • Quickstart - our guide for quickly adding Auth0 to your Express app.
  • Sample - an Express app integrated with Auth0.
  • FAQs - Frequently asked questions about express-openid-connect.
  • Docs Site - explore our docs site and learn more about Auth0.

Getting Started

Requirements

This library supports the following tooling versions:

  • Node.js ^10.19.0 || >=12.0.0

Install

Using npm in your project directory, run the following command:

npm install express-openid-connect

Getting Started

Follow our Secure Local Development guide to ensure that applications using this library are running over secure channels (HTTPS URLs). Applications using this library without HTTPS may experience "invalid state" errors.

Configure Auth0

Create a Regular Web Application in the Auth0 Dashboard.

If you're using an existing application, verify that you have configured the following settings in your Regular Web Application:

  • Click on the "Settings" tab of your application's page.
  • Ensure that "Authentication Methods" setting in the "Credentials" tab is set to "None"
  • Scroll down and click on the "Show Advanced Settings" link.
  • Under "Advanced Settings", click on the "OAuth" tab.
  • Ensure that "JsonWebToken Signature Algorithm" is set to RS256 and that "OIDC Conformant" is enabled. Next, configure the following URLs for your application under the "Application URIs" section of the "Settings" page:
  • Allowed Callback URLs: http://localhost:3000
  • Allowed Logout URLs: http://localhost:3000

These URLs should reflect the origins that your application is running on. Allowed Callback URLs may also include a path, depending on where you're handling the callback (see below).

Take note of the Client ID and Domain values under the "Basic Information" section. You'll need these values in the next step.

Configuring the SDK

The library needs issuerBaseURL, baseURL, clientID and secret to request and accept authentication. These can be configured with environmental variables:

ISSUER_BASE_URL=https://YOUR_DOMAIN
CLIENT_ID=YOUR_CLIENT_ID
BASE_URL=https://YOUR_APPLICATION_ROOT_URL
SECRET=LONG_RANDOM_VALUE

... or in the library initialization:

// index.js

const { auth } = require('express-openid-connect');
app.use(
  auth({
    issuerBaseURL: 'https://YOUR_DOMAIN',
    baseURL: 'https://YOUR_APPLICATION_ROOT_URL',
    clientID: 'YOUR_CLIENT_ID',
    secret: 'LONG_RANDOM_STRING',
    idpLogout: true,
  })
);

With this basic configuration, your application will require authentication for all routes and store the user identity in an encrypted and signed cookie.

Error Handling

Errors raised by this library are handled by the default Express error handler which, in the interests of security, does not include the stack trace or error message in the production environment. If you write your own error handler, you should not render the error message or the OAuth error/error_description properties without using a templating engine that will properly escape them first.

To write your own error handler, see the Express documentation on writing Custom error handlers.

For other comprehensive examples such as route-specific authentication, custom application session handling, requesting and using access tokens for external APIs, and more, see the EXAMPLES.md document.

See the examples for route-specific authentication, custom application session handling, requesting and using access tokens for external APIs, and more.

Use of Custom Session Stores and genid

If you create your own session id when using Custom Session Stores by overriding the genid configuration, you must use a suitable cryptographically strong random value of sufficient size to prevent collisions and reduce the ability to hijack a session by guessing the session ID.

API Reference

Explore the express-openid-connect API.

Provided middleware:

Feedback

Contributing

We appreciate feedback and contribution to this repo! Before you get started, please see the following:

Raise an issue

To provide feedback or report a bug, please raise an issue on our issue tracker.

Vulnerability Reporting

Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.

What is Auth0?

Auth0 Logo

Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?

This project is licensed under the MIT license. See the LICENSE file for more info.