Okta Node.js OIDC Middleware

raw JSON →
0.1.3 verified Thu Apr 23 auth: no javascript

The `@okta/oidc-middleware` package provides an OpenID Connect middleware for Express.js applications, simplifying the integration of Okta's authorization code flow. It handles redirecting users to Okta for authentication, processing the callback, and establishing a local session to store user context. The library currently maintains a stable major version series of 2.x, with the latest release being 4.2.0, following semantic versioning and Okta's library version policy. A key differentiator is its seamless integration with Express, managing OIDC complexities like token exchange and session maintenance, while relying on `express-session` for local session storage. It's designed to quickly enable secure authentication for Node.js web applications, abstracting away much of the underlying OIDC protocol details.

error Error: secret must be set for session middleware
cause The `express-session` middleware requires a `secret` option, which was either omitted or empty.
fix
Provide a strong, long, and securely generated secret string for express-session. Use environment variables to manage it: secret: process.env.SESSION_SECRET.
error TypeError: Cannot read properties of undefined (reading 'userContext')
cause The `req.userContext` object is not available, meaning the OIDC authentication flow has not completed or `oidc.router` was not properly configured/applied.
fix
Ensure app.use(oidc.router) is called, and that express-session middleware is registered *before* oidc.router. Verify that the user has successfully logged in via Okta and completed the OIDC redirect flow.
error No KID specified
cause The JWT (ID Token or Access Token) received from Okta or another source does not contain a 'kid' (Key ID) header, and `@okta/jwt-verifier` is configured to expect one.
fix
Verify that your Okta Authorization Server is configured to include 'kid' headers in issued tokens. If you're using custom tokens, ensure they adhere to this standard. This typically requires no change for standard Okta configurations.
error Error: Not found: /login (or any configured OIDC endpoint)
cause The OIDC endpoints (e.g., `/login`, `/authorization-code/callback`, `/logout`) are not correctly routed by the `oidc.router` middleware.
fix
Ensure app.use(oidc.router) is called in your Express application. Check your appBaseUrl configuration to ensure it matches your application's base URL and redirect URIs in Okta.
breaking The `@okta/jwt-verifier` dependency (v2.0.0 and higher) will now throw an error "No KID specified" if a JWT token lacks a 'kid' (Key ID) header. This is a breaking change for applications that receive tokens without 'kid' headers.
fix Ensure your Okta authorization server is configured to issue JWTs with a 'kid' header in the token. If using custom tokens, ensure they conform to this expectation. Upgrade to the latest stable versions of both `@okta/oidc-middleware` and `@okta/jwt-verifier`.
deprecated Versions 0.x and 1.x of `@okta/oidc-middleware` are considered deprecated or retired and should not be used in new projects or production environments due to potential security vulnerabilities and lack of maintenance.
fix Upgrade to the current stable major version series, which is 2.x or higher (latest is 4.x), to ensure you receive security updates and bug fixes.
gotcha The default `MemoryStore` provided by `express-session` is explicitly not designed for production use. Using it in production can lead to session loss on server restarts, scaling issues, and potential security vulnerabilities.
fix For production deployments, configure `express-session` with a persistent and robust session store like `connect-redis`, `connect-mongo`, or another compatible solution.
gotcha Older versions of `@okta/jwt-verifier` and its sub-dependencies, such as `jwks-rsa`, have contained security vulnerabilities that were addressed in later patches. Running outdated versions can expose your application to known exploits.
fix Always use the latest stable version of `@okta/oidc-middleware` to ensure all underlying dependencies are up-to-date with security patches. Regularly review dependency updates.
breaking The `onSessionExpired` behavior in `@okta/okta-react` (part of the same monorepo) was removed in version 3.0.4. While not directly `oidc-middleware`, it indicates a pattern of changes in how session expiration is handled across Okta libraries. Developers should review their session management strategy.
fix Consult the specific library's README for current guidance on handling session expiration. For `@okta/oidc-middleware`, custom logic might be required around session invalidation or token refresh.
npm install okta-oidc-middleware
yarn add okta-oidc-middleware
pnpm add okta-oidc-middleware

This example initializes an Express application with `express-session` and `@okta/oidc-middleware`, configuring a basic OIDC flow for user login and a protected route.

const express = require('express');
const session = require('express-session');
const { ExpressOIDC } = require('@okta/oidc-middleware');

const app = express();

const oidc = new ExpressOIDC({
  issuer: process.env.OKTA_ISSUER || 'https://{yourOktaDomain}/oauth2/default',
  client_id: process.env.OKTA_CLIENT_ID || '{clientId}',
  client_secret: process.env.OKTA_CLIENT_SECRET || '{clientSecret}',
  appBaseUrl: process.env.OKTA_APP_BASE_URL || 'http://localhost:8080',
  scope: 'openid profile'
});

app.use(session({
  secret: process.env.SESSION_SECRET || 'a-very-long-random-string-that-you-should-change',
  resave: false,
  saveUninitialized: false
  // For production, replace MemoryStore with a persistent store (e.g., connect-redis)
}));
app.use(oidc.router);

app.get('/', (req, res) => {
  if (req.userContext) {
    res.send(`
      Hello ${req.userContext.userinfo.name}!
      <form method="POST" action="/logout">
        <button type="submit">Logout</button>
      </form>
    `);
  } else {
    res.send('Please <a href="/login">login</a>');
  }
});

app.get('/protected', oidc.ensureAuthenticated(), (req, res) => {
  res.send('This is a protected page. Welcome, ' + req.userContext.userinfo.name);
});

const port = process.env.PORT || 8080;
oidc.on('ready', () => {
  app.listen(port, () => console.log(`App has started on port ${port}`));
});
oidc.on('error', err => {
  console.error('OIDC error: ', err);
});