Skip to content

[BUGFIX] Skip bearer auth flow when Authorization header is absent#150

Open
uluzox wants to merge 1 commit into
FriendsOfTYPO3:masterfrom
uluzox:bugfix/bearer-auth-null-scheme
Open

[BUGFIX] Skip bearer auth flow when Authorization header is absent#150
uluzox wants to merge 1 commit into
FriendsOfTYPO3:masterfrom
uluzox:bugfix/bearer-auth-null-scheme

Conversation

@uluzox
Copy link
Copy Markdown

@uluzox uluzox commented May 13, 2026

Problem

HttpBackendUserAuthentication::checkAuthentication() unconditionally calls
authenticateBearerToken() on every incoming request. That method extracts an
Authorization header, destructures the scheme and token, and is supposed to
early-return for any auth scheme that is not bearer — letting the parent
authentication handler take over.

The existing guard does not handle a missing Authorization header:

[$scheme, $token] = GeneralUtility::trimExplode(' ', $authorizationHeader, true);

if (is_string($scheme) && strtolower($scheme) !== 'bearer') {
    return;
}

When the header is empty or absent, trimExplode(' ', '', true) returns [],
so $scheme and $token are both null. is_string($scheme) is then false,
the guard does not trigger, and the function falls through to:

$backendUserId = GeneralUtility::makeInstance(TokenRepository::class)
    ->findBackendUserIdByToken($token);   // $token === null

TokenRepository::findBackendUserIdByToken() is typed string $token, so PHP
raises a TypeError:

TypeError: FriendsOfTYPO3\Interest\Domain\Repository\TokenRepository::findBackendUserIdByToken():
Argument #1 ($token) must be of type string, null given,
called in .../HttpBackendUserAuthentication.php on line 123

This surfaces in production whenever a request reaches the extension without a
forwardable Authorization header — for example when an Apache mod_proxy_fcgi
deployment hasn't set CGIPassAuth On and silently drops the header before it
gets to PHP. The TypeError is shown to the client instead of letting the parent
authentication flow respond normally.

Fix

Add an explicit null-check right after the trimExplode destructure. The
existing scheme/bearer comparison stays untouched:

[$scheme, $token] = GeneralUtility::trimExplode(' ', $authorizationHeader, true);

if ($scheme === null) {
    return;
}

if (is_string($scheme) && strtolower($scheme) !== 'bearer') {
    return;
}

This mirrors the pattern used in getLoginFormData() of the same class, where
the "no scheme provided" case is handled before the scheme value is compared.

No behaviour change for valid Bearer <token> headers; no behaviour change for
other valid schemes (Basic … etc. — still early-return via the second guard).
The only newly handled case is the previously-crashing one: no scheme present.

Why no test in this PR

There is no existing unit/functional test for HttpBackendUserAuthentication,
and the class extends TYPO3\CMS\Core\Authentication\BackendUserAuthentication,
which makes constructing it in a unit test non-trivial (its parent does I/O).
Happy to add a test in a follow-up if reviewers prefer — likely a functional
test that issues a request without an Authorization header against a routed
endpoint and asserts no TypeError.

Repro (production)

curl -X POST https://<typo3>/rest/authenticate

— without Authorization header → before this patch: 500 / TypeError;
after: passes through to the parent auth flow as intended.

@uluzox uluzox force-pushed the bugfix/bearer-auth-null-scheme branch 2 times, most recently from 1919ff4 to 2c0df5b Compare May 13, 2026 07:47
authenticateBearerToken() destructures the scheme and token from the
Authorization header. The existing guard returned early only when a
scheme was present but did not equal "bearer". For requests without
an Authorization header (or with an unparseable header that yields no
scheme), $scheme is null, the guard did not trigger, and the function
fell through to TokenRepository::findBackendUserIdByToken(null) which
raised a TypeError because the argument is typed as string.

Add an explicit null-check directly after the trimExplode destructure.
The existing scheme/bearer comparison stays untouched. This mirrors
the pattern used in getLoginFormData() of the same class, where the
"no scheme provided" case is handled before the scheme value is
compared.
@uluzox uluzox force-pushed the bugfix/bearer-auth-null-scheme branch from 2c0df5b to 566a3e2 Compare May 13, 2026 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant