Skip to content

State handle can contain '+' which breaks some OIDC providers #118

@shinmawa

Description

@shinmawa

In utils.js, there is this function, which is used to create state handles:

exports.uid = function(len) {
  return crypto.randomBytes(Math.ceil(len * 3 / 4))
    .toString('base64')
    .slice(0, len);
};

This has the capability to create handles with a "+" character in it. Some OIDC providers (e.g. IBM App ID) can put the handle in the GET string and when redirected back, req.query.handle will have all the "+" characters replaced with spaces.

For example, the session may have the handle w8N7RC7Q+WM5+SPH2ZxgBs7V while req.query.handle will have the value w8N7RC7Q WM5 SPH2ZxgBs7V. State verification fails as they do not match.

  var state = req.session[key].state;

  // ... lines deleted ...

  if (state.handle !== handle) {
   return cb(null, false, { message: 'Invalid authorization request state.' });
  }

Here's a real time example from a log:

2025-04-01 16:22:40 [debug]:    Current session: {"cookie":{"originalMaxAge":null,"expires":null,"httpOnly":true,"path":"/"},"openidconnect:us-east.appid.cloud.ibm.com":{"state":{"handle":"K5B2+sp3S93Z0weYTL4/zmnk"}}}
2025-04-01 16:22:40 [debug]:    Req Query: {"code":"<code deleted>","state":"K5B2 sp3S93Z0weYTL4/zmnk"}

The fix:

Replace 'base64' with 'base64url' in utils.js

exports.uid = function(len) {
  return crypto.randomBytes(Math.ceil(len * 3 / 4))
    .toString('base64url')
    .slice(0, len);
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions