Skip to content

tokens function not called when Authorization header is not in Bearer format #5595

@AuspeXeu

Description

@AuspeXeu

Current Behavior

Description

The documentation for custom authentication tokens states:

By default, it will use the Authorization http header and expect a Bearer type
token - passing in just the value of the token to the function. If it is not a
Bearer type token, then the full value of the Authorization header will be
passed to the function, containing both type and value.

This implies that any value in the Authorization header will eventually reach the
user-defined tokens() function. This is not the case.

Root Cause

Authentication is handled in needsPermission() in
packages/node_modules/@node-red/editor-api/lib/auth/index.js, which runs passport
strategies in this order:

passport.authenticate(['bearer', 'tokens', 'anon'], { session: false })

The bearer strategy is provided by the third-party package
passport-http-bearer.
Looking at its implementation in lib/strategy.js:

var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
    if (/^Bearer$/i.test(scheme)) {
        token = credentials;
    }
} else {
    return this.fail(400);  // ← hard 400, chain stops here
}

If the Authorization header is present but not in exactly Bearer <token> format,
passport-http-bearer calls this.fail(400), which immediately returns a 400
response to the client
. The passport strategy chain is aborted — the tokens and
anon strategies never run, and the user-defined tokens() function is never called.

Impact

Any reverse proxy or integration that forwards a non-Bearer Authorization header
(e.g. a raw token, Basic auth, or a custom scheme) will receive a 400 response,
regardless of whether their tokens() function would have accepted it. The docs
explicitly promise this use case is supported.

Steps to Reproduce

  1. Configure adminAuth with a tokens function that logs its input and accepts any value:
   adminAuth: {
       tokens: function(token) {
           console.log("tokens() called with:", token);
           return Promise.resolve({ username: "admin", permissions: "*" });
       }
   }
  1. Send a request with a non-Bearer Authorization header:
   curl -H "Authorization: myrawtoken" http://localhost:1880/settings
  1. Observe that the response is 400, and tokens() is never called.

Expected Behaviour

Per the documentation, the full value of the Authorization header should be passed
to the tokens() function when it is not a Bearer type token.

Actual Behaviour

A 400 is returned immediately by passport-http-bearer before the tokens() function
is ever invoked.

Environment

  • Node-RED version: 4.1.7

Expected Behavior

No response

Steps To Reproduce

No response

Example flow

paste your flow here

Environment

  • Node-RED version:
  • Node.js version:
  • npm version:
  • Platform/OS:
  • Browser:

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions