137

I am currently developing a REST-API which is HTTP-Basic protected for the development environment. As the real authentication is done via a token, I'm still trying to figure out, how to send two authorization headers.

I have tried this one:

curl -i http://dev.myapp.com/api/users \
  -H "Authorization: Basic Ym9zY236Ym9zY28=" \
  -H "Authorization: Bearer mytoken123"

I could for example disable the HTTP-Authentication for my IP but as I usually work in different environments with dynamic IPs, this is not a good solution. So am I missing something?

Morten Jensen
  • 5,111
  • 3
  • 38
  • 51
Azngeek
  • 1,607
  • 2
  • 11
  • 11
  • There are many ways to do authentication (not to be confused with authirization) over http. Are you usibg some kind of framework or is this your own creation? why do you need two authorization-headers? – plc Mar 06 '14 at 16:26
  • 2
    I need to authenticate via HTTP Basic as the Dev server is protected with it and i need the token based authentication for the api. But as i use curl to test the api, i need a way to send both authentication header. So the first one (basic) to pass HTTP Basic and the second one (token) to authenticate to my application. And yes, it is my own creation. – Azngeek Mar 06 '14 at 21:41
  • 1
    You ever figure this out? I'm adding a bounty – Adam Waite Mar 21 '14 at 14:31
  • 4
    Hello Adam, unfortunately not. I have now changed the way the authentication works by changing my Authorization Header for the token to "x-auth" which is not a standard header. – Azngeek Mar 21 '14 at 16:30
  • I just decided to scratch the entire HTTP basic auth in the end too – Adam Waite Mar 27 '14 at 19:15
  • 1
    My nginx server won't even accept 2 Authorization headers. It returns a `400 Bad request`. Silly. – Rudie Jun 12 '15 at 22:04
  • 1
    What's wrong with using a custom header for your API token? I don't see why the people here have "scrapped" using HTTP Basic Auth to keep their development/staging servers away from prying eyes. – Sunil D. Jan 13 '16 at 18:03
  • You should just be able to use a single header with a comma between auth types - see https://stackoverflow.com/questions/29282578/multiple-http-authorization-headers/38515091#38515091 – Sam Critchley Jun 07 '17 at 10:21
  • base64decode (Ym9zY236Ym9zY28=) gives boscmbosco – Ganesh Kamath - 'Code Frenzy' Dec 19 '20 at 05:11

7 Answers7

81

Try this one to push basic authentication at url:

curl -i http://username:password@dev.myapp.com/api/users -H "Authorization: Bearer mytoken123"
               ^^^^^^^^^^^^^^^^^^

If above one doesn't work, then you have nothing to do with it. So try the following alternates.

You can pass the token under another name. Because you are handling the authorization from your Application. So you can easily use this flexibility for this special purpose.

curl -i http://dev.myapp.com/api/users \
  -H "Authorization: Basic Ym9zY236Ym9zY28=" \
  -H "Application-Authorization: mytoken123"

Notice I have changed the header into Application-Authorization. So from your application catch the token under that header and process what you need to do.

Another thing you can do is, to pass the token through the POST parameters and grab the parameter's value from the Server side. For example passing token with curl post parameter:

-d "auth-token=mytoken123"
Sabuj Hassan
  • 35,286
  • 11
  • 68
  • 78
  • 1
    Hello Sabuj, the issue is not the way how you pass the username and password but multiple authorization headers just dont work. Looking at the specs (https://www.ietf.org/rfc/rfc2617.txt) i can see that this should be possible. But as also stated ""The user agent MUST choose to use one of the challenges with the strongest auth-scheme it understands and request credentials from the user based upon that challenge." So like i have written 2 days ago i needed to pass the token to a non-standard header which is absolutely okay when you deal with non-standard architectures. – Azngeek Mar 24 '14 at 11:28
  • 5
    @Azngeek Curl does send both the authorization headers when you perform the task. You need to handle it from your server's end. Just run your curl command with both headers with `-v` param. You'll find that its sending `Authorization: Basic Ym9zY236Ym9zY28=, Authorization: Bearer mytoken123` at request header. From your server end, if you check, you'll find that you have Authorization header like this way `Authorization: Basic Ym9zY236Ym9zY28=, Bearer mytoken123` separated by comma. So, I though I should suggest you alternates. – Sabuj Hassan Mar 25 '14 at 17:44
35

Standard (https://tools.ietf.org/html/rfc6750) says you can use:

  • Form-Encoded Body Parameter: Authorization: Bearer mytoken123
  • URI Query Parameter: access_token=mytoken123

So it's possible to pass many Bearer Token with URI, but doing this is discouraged (see section 5 in the standard).

Mark Stosberg
  • 11,351
  • 6
  • 37
  • 47
Janek Olszak
  • 3,275
  • 1
  • 23
  • 21
5

If you are using a reverse proxy such as nginx in between, you could define a custom token, such as X-API-Token.

In nginx you would rewrite it for the upstream proxy (your rest api) to be just auth:

proxy_set_header Authorization $http_x_api_token;

... while nginx can use the original Authorization header to check HTTP AUth.

shredding
  • 4,376
  • 3
  • 36
  • 66
3

I had a similar problem - authenticate device and user at device. I used a Cookie header alongside an Authorization: Bearer... header. One header authenticated the device, the other authenticated the user. I used a Cookie header because these are commonly used for authentication.

Iiridayn
  • 1,590
  • 19
  • 39
  • Not clear why the downvote. I came across this question searching for an answer to a related problem - this is how I resolved it. The `Cookie` header is already frequently used for authentication. – Iiridayn Nov 26 '18 at 18:55
  • i think the problem for some people is that they like me don't know what you send as cookie - the same as the header or only a token or anything else? – René W. Feb 05 '21 at 21:56
2

curl --anyauth

Tells curl to figure out authentication method by itself, and use the most secure one the remote site claims to support. This is done by first doing a request and checking the response- headers, thus possibly inducing an extra network round-trip. This is used instead of setting a specific authentication method, which you can do with --basic, --digest, --ntlm, and --negotiate.

bbaassssiiee
  • 4,879
  • 1
  • 34
  • 46
1

There is another solution for testing APIs on development server.

  • Set HTTP Basic Authentication only for web routes
  • Leave all API routes free from authentication

Web server configuration for nginx and Laravel would be like this:

    location /api {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location / {
        try_files $uri $uri/ /index.php?$query_string;

        auth_basic "Enter password";
        auth_basic_user_file /path/to/.htpasswd;
    }

Authorization: Bearer will do the job of defending the development server against web crawlers and other unwanted visitors.

1

With nginx you can send both tokens like this (even though it's against the standard):

Authorization: Basic basic-token,Bearer bearer-token

This works as long as the basic token is first - nginx successfully forwards it to the application server.

And then you need to make sure your application can properly extract the Bearer from the above string.

Tomov
  • 2,148
  • 23
  • 34