4

We're setting up the Okta oidc-middleware for our web app.

What works is when we're not logged in, we get redirected to Okta, and then we're redirected back to our callback handler after providing valid credentials. When testing locally, the callback receives the auth code and we're redirected to the after callback path.

However on our deployed staging server, the callback receives the code but returns a 401.

Here's a similar issue that's currently open: https://github.com/okta/okta-oidc-js/issues/207

May or may not be related to that, the situation described isn't exactly the same, though the error message is the same.

Does anyone have thoughts on what the issue might be or how to bump up the verbosity level of the logging?

I don't think it's due to misconfiguration of the Login redirect URIs. We've added the requisite paths.

The Okta config in our Express settings are something like this:

const MemoryStore = require('memorystore')(session);
app.use(
  session({
    store: new MemoryStore({
      checkPeriod: 86400000,
    }),
    secret: process.env.OKTA_SESSION_SECRET,
    resave: true,
    saveUninitialized: false,
    cookie: {
      maxAge: 30 * 60 * 1000,
      httpOnly: false,
    },
  })
);

const orgUrl = process.env.OKTA_ORG_URL;
const oidc = new ExpressOIDC({
  appBaseUrl: process.env.OKTA_APP_BASE_URL,
  issuer: `${orgUrl}/oauth2/default`,
  client_id: process.env.OKTA_CLIENT_ID,
  client_secret: process.env.OKTA_CLIENT_SECRET,
  scope: 'openid profile',
  routes: {
    login: {
      path: `${APP_ROOT}/login`,
    },
    loginCallback: {
      path: `${APP_ROOT}/authorization-callback`,
      afterCallback: APP_ROOT,
    },
  },
});
app.use(oidc.router);

Here is the error that pops up in server logs:

Error: state mismatch, could not find a state in the session, this is likely an environment setup issue, loaded session: undefined
    at callback.then.catch (/usr/src/app/node_modules/openid-client/lib/passport_strategy.js:169:20)
    at <anonymous>
    at runMicrotasksCallback (internal/process/next_tick.js:121:5)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickDomainCallback (internal/process/next_tick.js:218:9)
Thinh Ngo
  • 41
  • 1
  • 3

2 Answers2

3

To protect from CSRF attack, OAUTH 2.0 expects the client to generate a random "state", store it in session, and send it to your IdP as an argument to the authentication endpoint.

when the IdP returns the response, it echoes the same state the client sent. If they are different, the authentication is rejected.

Your issue seem to indicate that this state parameter was not stored properly in the client's session.

maybe you have multiple instances of the node backend, but don't have a sticky session? in this case, the instance who stored the state in the session might not be the same instance who gets back the response callback from IdP.

Liran Brimer
  • 3,418
  • 1
  • 28
  • 23
0

Since our deployed server is proxied through at least one layer of servers, state info got lost in transition. We resolved by using: https://github.com/expressjs/cookie-session

Thinh Ngo
  • 41
  • 1
  • 3