If I'm reading this correctly, the issue is the formatting, your correct in your guess.
const authorizationHeader = req.headers.authorization || '';
const idToken = authorizationHeader.startsWith('Bearer ')
? authorizationHeader.split('Bearer ')[1]
: null;
This part of your code will return as the value for idToken as either a 'Bearer ' stripped id, or null.
If you passed in your test case value you use:
$idTokenDirect = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjNmO..." # Pasted full, verified token
Then I think what this would do is set idToken to null. And that would explain why you're seeing what you're seeing.
Now if you sent in a
'Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjNmO...'
style, you should get the 'eyJhG....' stuff as element 1, like your code implies, as the value for idToken.
However, I don't see you prepending 'Bearer ' back in front of the idToken ever, and you do use this in your testing script.
Seems like this is the disconnect between the two flows? If you need "Bearer " in the auth call, then perhaps reverse the testing at the top to see if it's missing and add it, instead of stripping it off if it exists?