I'm designing a REST API using authorization/authentication via an API Key.
I tried to figure out what is the best place for it and found out that many people suggest using a custom HTTP header such as ProjectName-Api-Key
, eg:
ProjectName-Api-Key: abcde
but also it's possible and ideologically correct to use the Authorization
header with a custom scheme, eg:
Authorization: ApiKey abcde
On the other hand, I found a consideration that a custom Authorization scheme can be unexpected and unsupported by some clients and leads to custom code anyway, so it's better to use a custom header since clients don't have any expectations about it.
Which way would you prefer to send an API Key?
1 Answer 1
Be consistent
Some may say this is unnecessary (and not too long ago I would have agreed) but these days, with so many auth protocols, if we use the Authorization
header to pass an API key, it is worth informing the type too because API keys are not self-descriptive per se 1.
Why do I think it is worth it? Because nowadays supporting different authentication or/and authorization protocols has become a must-have. If we plan to use the Authorization
header for all these protocols, we have to make our auth service consistent. The way to communicate what kind of token we send and what authorization protocol should be applied should go in the header too.
Authorization: Basic XXXX
Authorization: Digest XXXX
Authorization: Bearer XXXX
Authorization: ApiKey-v1 XXXX
Authorization: ApiKey-v2 XXXX
I used to don't care about this, but after working with mobile clients or sensors, in which updates were not guaranteed, I started to. I started to be more consistent in the way I implement security so that I can keep backwards compatibility. With the token's type informed I can invalidate requests from a specific set of clients (the outdated ones), add new schemes and differentiate old clients from new ones and change auth validations for one or another scheme without causing breaking changes. I also can apply specific rules in the API Gateways based on the authorization scheme. For example, I can redirect old schemes to specific versions of my web APIs which are deployed apart from the main ones.
Concerns
The problems I faced implementing my own schemes have been similar to the one commented.
On the other hand, I found a consideration that a custom Authorization scheme can be unexpected and unsupported by some clients and leads to custom code anyway
Say clients, say libraries, frameworks, reverse proxies. A custom header can be rejected or ignored. In the worse of the cases, it can also collide.
Collisions can be problematic, but all other issues are likely to be solved by tackling configurations.
Advantages
One important advantage is cache. Shared caches won't cache the header (and that's good of course) unless you say otherwise.
So Authorization or custom header?
In my experience, both take me almost the same work and time to implement, with a slight difference. I had more room for design when I implemented custom headers. However, more room for design also meant more chances to overcomplicate things or reinvent the wheel.
Technically, there could be very little or no difference between the two, but I have found the consistency to be a good feature. It provides me with clearness and understanding. In my case, adding new schemes was reduced to adding 2 new abstractions (implemented by the same concrete class): TokenHandler and TokenValidator. The Handler
only checks whether the request header Authorization
informs the supported scheme. The Validator
is anything I need to validate the token. Altogether working from a single request filter instead of a chain of filters or a big ball of mud.
1: I find this answer to be very clear regarding API Keys
-
9The using of
X-
is deprecated as of 2012: stackoverflow.com/a/3561399/923720Dani– Dani2017年07月20日 14:26:37 +00:00Commented Jul 20, 2017 at 14:26 -
2ops! I didn't know. Edited and fixed.Laiv– Laiv2017年07月20日 14:34:34 +00:00Commented Jul 20, 2017 at 14:34
-
Before this question I thought most everybody put the API key in the URL, but used HTTPS to hide it. Good to see some alternatives. For example, Contentful allows Authorization or query pamameter: contentful.com/developers/docs/references/content-delivery-api/…user949300– user9493002017年11月29日 22:36:46 +00:00Commented Nov 29, 2017 at 22:36
-
1@user949300 ...using an encrypted shared secret (e.g. api key in uri over ssl) is obviously more secure than nothing at all, but is easily spoofable if it is intercepted and provides no granularity over identities. I have never used api_keys for anything other than machine to machine communication where I am matching the shared secret between trusting parties and the whitelisted machine identities authorized to act with that shared secret. After the machine to machine conn is made, the human operator authenticates using other means.K. Alan Bates– K. Alan Bates2017年11月30日 03:18:29 +00:00Commented Nov 30, 2017 at 3:18
-
2There is a difference in how CORS operates w/ custom headers vs the Authorization header. In the response to a preflight CORS OPTION request, the Authorization header is not included in the wildcard (*) response and must be explicitly sent.Andrew Martinez– Andrew Martinez2021年03月17日 17:09:27 +00:00Commented Mar 17, 2021 at 17:09
Explore related questions
See similar questions with these tags.
Authorization: Bearer <token>
header and there was never a single issue with that. The tokens are JWTs.Bearer
scheme is used exclusively with oAuth2. Applying it separately from oAuth sounds as misusing it. Why is it correct to use this scheme if there is no oAuth? By the way, I had troubles with choosing a type of authorization for my API. The API will be available only for one trusted service, so I investigated the client credentials flow of oAuth2 and haven't found any benefit in comparison with ApiKey in my case.ApiKey
was renamed and interpreted as anAccess Token
granted to the client without an expiration time. That's a kind of philosophical aspect, I decided not to bring complex definitions if my case can be described in simple terms and decided to just call it "ApiKey". If your protocol implements oAuth standart, I can agree on usingBearer
, but it doesn't, I guess this scheme can't be applied.