Search code examples
node.jsexpressurl-encodingbasic-authentication

How to handle HTTP Basic Auth with URL encoding in Express (Node.js)


I'm receiving callbacks from an API we're using (Adobe Sign API). The only method available to authenticate these callbacks is HTTP Basic Auth, using URL encoding (not headers).

Documentation:

callbackInfo (string, optional): A publicly accessible url to which Adobe Sign will do an HTTP GET operation every time there is a new agreement event. HTTP authentication is supported using standard embedded syntax - i.e. http://username:[email protected]/path/to/file.

How can I access the username:password@ part of the URL, in order to validate the credentials? It doesn't seem to be available from the Request object (I dumped the entire object to console.error() and can't find the credentials anywhere in there). :(

I'm using Express 4.14.0, npm 3.10.8 & Node.js 7.0.0 (I could upgrade to a newer version if that would help).

Unfortunately, the Adobe Sign support is not helpful at all.

Edit: I already support the HTTP Basic authentication header (Authorization), but once again, it is not provided in this callback. Requests using the header show up in my nginx access logs with the username, but the callback doesn't show any username (which makes sense since the header isn't there). The only credentials available are in the username:password@ part of the URL. I didn't even know this was possible, but apparently it's part of the URL RFC, and still supported today (see section 3.1. Common Internet Scheme Syntax). I'm literally just receiving a simple GET request with no headers at all. Something like https://adobesign:[email protected]/callbacks.

For failed authentications, I'm returning a 401 response with the WWW-Authenticate header set to Basic, but it doesn't help in this case (only makes browsers prompt for username/password, but doesn't affect the callback).


Solution

  • That is part of the URL RFC yes, as in a URL can define a username and password, but it's up to the protocol to send it. HTTP doesn't support what you're describing, it only sends HTTP auth via the Authorization header. Something else is broken, perhaps something is stripping the header before it gets to you, perhaps Adobe Sign is sending something unexpected, etc. But there's no mechanism for HTTP to transfer that username / password except in a header. It's just not in the protocol.

    Also, you said you dumped the entire request to the console, try dumping the auth header with console.log(req.get('Authorization')); You may not have seen the username / password value in the console as it's combined with a colon and base64 encoded before sending, so you won't see the plain text in your console.

    You may also want https://github.com/expressjs/basic-auth-connect to more easily process the authorization request.