{ Community }
  • Academy
  • Docs
  • Developers
  • Resources
    • Community Articles
    • Apigee on GitHub
    • Code Samples
    • Videos & eBooks
    • Accelerator Methodology
  • Support
  • Ask a Question
  • Spaces
    • Product Announcements
    • General
    • Edge/API Management
    • Developer Portal (Drupal-based)
    • Developer Portal (Integrated)
    • API Design
    • APIM on Istio
    • Extensions
    • Business of APIs
    • Academy/Certification
    • Adapter for Envoy
    • Analytics
    • Events
    • Hybrid
    • Integration (AWS, PCF, Etc.)
    • Microgateway
    • Monetization
    • Private Cloud Deployment
    • 日本語コミュニティ
    • Insights
    • IoT Apigee Link
    • BaaS/Usergrid
    • BaaS Transition/Migration
    • Apigee-127
    • New Customers
    • Topics
    • Questions
    • Articles
    • Ideas
    • Leaderboard
    • Badges
  • Log in
  • Sign up

Get answers, ideas, and support from the Apigee Community

  • Home /
  • Edge/API Management /
avatar image
0
Question by tpearson · Jul 23, 2015 at 07:33 PM · 60.5k Views authenticationheadersapikeyhttp

How-to comply with HTTP standard when putting the API key in a header

Right now, we only allow clients to send API keys to our Edge proxy using only the apikey query parameter.

This makes it difficult for clients to keep their APIkeys secret, they tend to leak keys on a regular basis. Both ourselves and some of our clients believe it's a good idea to support passing API keys in the headers, where they will benefit from the security of HTTPS, although we will also continue to support the key as a query parameter.

I started investigating how to do this correctly, and reading the HTTP specs I think a correct way to do this would be to use the authorization header, presumably something like:

Authorization : APIKEY your-api-key-here

I notice this is not the way that is suggested in your documentation. Is there a reason for that (eg. client ease-of-use)? What are the advantages / disadvantages using the apikey header vs the Authorization header?

I also notice that default status response for an invalid apikey parameter is HTTP 401, unauthorized. However, this requires that the response headers include a suggested authentication method, which is also not configured. Are there any consequences to not providing this header?

Comment
Add comment
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Close

5 Answers

  • Sort: 
avatar image
4

Answer by Dino   · Jul 23, 2015 at 10:54 PM

There is no single, "correct" way to pass in authentication information including APIKeys. This is true for any HTTP API, whether managed in Apigee Edge or not.

As you know, your policies in Apigee Edge can access any part of the inbound message: query parameters, headers, payload, url path elements, and methods.

You can choose any one of those options.

You mentioned "key leakage" as a problem. for sure, eliminating the possibility to transmit keys in the query string is a good idea. Also, using TLS to secure the transport layer may also be recommended.

As for whether using the Authorization header WITH an APIKEY prefix is necessary. The spec recommends it, so obviously it's not *wrong*, but it does seem like an extra bit of formality and strictness that isn't contributing any value to either the caller or the receiver. And maybe it is contributing some "cost" in terms of complexity. In particular on the caller side, the developer would need to add that prefix to every call. (one extra string concatenation). On the server side, you would need the converse - a string split - and then you'd need to validate that the prefix was the prefix you were expecting: Apikey and none other. What is the point of all this extra framing? To me, the simplest thing that works is the best, and this APIKEY prefix would represent extra framing.

The prefix seems like it would be a really good idea if your API endpoint needed to handle multiple distinct kinds of authentication: Key, Token, Signature, and so on. And all of them were alternatives, that could be requested via different values in the same request header. There, the prefix disambiguates the remaining payload of the header. However, if your API doesn't support multiple auth values, then it just seems like an unnecessary extra bit of protocol.

You may say: what if, in the future, I would like to introduce a new authentication mechanism, distinct from APIKey? Wouldn't it be smart to use the prefix now to allow this future possibility? Here, I think YAGNI applies. Even if you implement an extension like this in the future, you can introduce prefixes THEN, and any header with no prefix, just treat as an APIKey by default. So there's still no problem. And if the purist in you insists on always including a prefix if any of the Authentication headers require a prefix, why, you could simply increment the API revision to handle that case.

So in summary, "meh" on the APIKEY prefix.

The counter-argument is obviously "OAuth v2 uses the Bearer prefix". Quite true, but all of my reasoning applies there as well. It's still unnecessary. But there are lots of tools that know how to build or parse "standard" OAuthV2 headers, so that prefix will likely remain. (In Apigee Edge, the policy that verifies an OAuthV2 token by default expects to find and strip out the Bearer prefix, but you can configure it to expect a different prefix, or no prefix).

Regarding rfc7235 and the recommendation to use the WWW-Authenticate response header, surely that is a good idea. That is a good practice which has been in use for some time. However, if you document your API correctly, it is not strictly necessary. You can simply state in the documentation how the caller needs to authenticate (pass a key, sign the request, etc), and a 401 Unauthorized need not be transmitted with additional information in the case of an authentication failure.

In other words, It might be developer-friendly to distinguish between a 401 because of a missing key, and a 401 because of an expired key, and a 401 because of an present-but-invalid key, but it is not strictly necessary.

Comment
Add comment Show 1 · Link
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by eiksanaK liamG truK · Jul 23, 2015 at 09:24 PM

We use the header param X-Merck-APIKey which seems to be a defacto convention.

Comment
Add comment Show 2 · Link
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Dino ♦♦   · Jul 23, 2015 at 10:57 PM 0
Link

Hi @Kurt Kanaskie

regarding that naming convention, you may wish to have a quick look at https://tools.ietf.org/html/rfc6648 . Apparently X- prefixes are soooo 2011.

avatar image eiksanaK liamG truK Dino ♦♦ · Jul 27, 2015 at 01:03 PM 0
Link

Oh man I'm such a noob.

From the spec, for private use, Merck-APIKey would make me hip :)

avatar image
1

Answer by ozanseymen   · Jul 24, 2015 at 09:43 AM

@tpearson - I couldn't understand how HTTP headers are more secure than query parameters? In TLS, both of them are encrypted.

Comment
Add comment · Link
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by tpearson · Jul 24, 2015 at 02:21 PM

Thanks everyone for the healthy debate.

@David Allen and @Ozan Seymen - thanks for the article and the tip. I had assumed that, because it was in the URL, the query parameter was not encrypted. Good to know that I'm wrong, that makes this task less urgent.

@Dino, thanks for the comprehensive response. We do actually use a second form of auth in some of our APIs, a legacy login system used by some of our backends. For this, we use the Authorization header with the LSS prefix. If I were to use the Authorization header for API keys, I think I would stick to the standard and add the APIKEY prefix, even though it does hurt ease-of-use.

Otherwise, if I'm going to ignore the sandard and focus on ease-of-use, a header along the lines of

Apikey: your-api-key-here

probably makes the most sense - it's simple, and it's consistent with the query parameter.

I don't have a preference right now, I'll think about if for a few days. Feel free to let me know your opinions on why I should choose one or the other.

Comment
Add comment Show 1 · Link
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image ozanseymen ♦♦   · Jul 28, 2015 at 07:55 PM 1
Link

@tpearson - everything apart from hostname and port (and IP) is encrypted. TLS sits on top of TCP so all HTTP protocol specific data is encrypted.

Check the 3rd paragraph under Overview heading in https://en.wikipedia.org/wiki/HTTPS.

avatar image
0

Answer by tpearson · Oct 12, 2015 at 06:38 PM

So, we looked into this some more. Taking an adhoc survey of how details are passed in our favorite APIs (Google Maps, Facebook Graph, Twitter, Amazon, Stripe, Yelp...) we found about 50% passing credentials and keys in a HTTP Authorization header, 30-40% passing keys in query parameters, and the rest either using HTTP basic or a custom header. So, clearly, a custom header is not the way to go. Either it goes in the query parameters, or in the Authorization header. Some APIs support both, presumably for those who haven't given up on JSONP.

The problem is, looking in the documentation, I don't see an obvious way to use the VerifyAPIKey policy with the Authorization header. Would I have to use a JS call (or something else) to locate the APIKey token manually and then bind the key into another variable for the VerifyAPIKey policy to check it? Or is there a better way?

Comment
Add comment Show 3 · Link
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image tpearson · Oct 13, 2015 at 07:09 PM 0
Link

@Dino, @David Allen, @Ozan Seymen- no suggestions?

avatar image ozanseymen ♦♦   · Oct 14, 2015 at 12:26 AM 2
Link

Hi @tpearson

Regarding your first paragraph - yes, unfortunately there is no "standard" way of doing this especially if we are talking about HTTP standard. This is left to the "imagination" and/or "personal preference" of developers. Everybody has their personal preference in this matter.

The only "technical" comment that I can make is - if you have apikeys in queryparams, there is a chance that it will be logged in http servers and/or intermediaries that the request is passing through. So it is something for you to think about if you are ok to have that (sometimes it is beneficial to have that for logging purposes, sometimes it is totally undesirable by security teams)

Coming to the second half of your comment, you haven't mentioned the structure of your Authorization header but if I assume you are directly putting the value in, e.g. Authorization: abcd123, then in Apigee, you can do request.header.Authorization. This variable will get the value of the apikey. So your policy will look like:

<VerifyAPIKey name="xyz">
    <APIKey ref="request.header.Authorization" />
</VerifyAPIKey>

If you are using any custom Authorization header extensions as it is described in in HTTP spec, then you might need to write a simple JS to extract the data yourself.

avatar image tpearson ozanseymen ♦♦ · Oct 27, 2015 at 09:03 PM 0
Link

Ouch. So if I want to support an Authorization header of the format matching the specs like

Authorization Apikey jeafkpejaffeajipfeja

as well as an apikey query parameter for backwards compatability. I have to

  1. Write the apikey query parameter into the Authorization header, if it doesn't already exist
  2. Parse the Authorization header to find the Apikey Authorization token, in case there are other tokens, and copy its value to a variable
  3. Verify that variable using the VerifyAPIKey policy

Does that sound correct?

Follow this Question

Answers Answers and Comments

27 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Added header values not getting in target endpoint 1 Answer

How can we pass dynamic access token to every API request through authentication? 1 Answer

Extract bearer token from Authorization when separated by multiple spaces 1 Answer

Implementing Basic Auth 3 Answers

Implementing Fault rules for Basic Auth policy and Verify Apikey 2 Answers

  • Products
    • Edge - APIs
    • Insights - Big Data
    • Plans
  • Developers
    • Overview
    • Documentation
  • Resources
    • Overview
    • Blog
    • Apigee Institute
    • Academy
    • Documentation
  • Company
    • Overview
    • Press
    • Customers
    • Partners
    • Team
    • Events
    • Careers
    • Contact Us
  • Support
    • Support Overview
    • Documentation
    • Status
    • Edge Support Portal
    • Privacy Policy
    • Terms & Conditions
© 2021 Apigee Corp. All rights reserved. - Apigee Community Terms of Use - Powered by AnswerHub
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Create an article
  • Post an idea
  • Spaces
  • Product Announcements
  • General
  • Edge/API Management
  • Developer Portal (Drupal-based)
  • Developer Portal (Integrated)
  • API Design
  • APIM on Istio
  • Extensions
  • Business of APIs
  • Academy/Certification
  • Adapter for Envoy
  • Analytics
  • Events
  • Hybrid
  • Integration (AWS, PCF, Etc.)
  • Microgateway
  • Monetization
  • Private Cloud Deployment
  • 日本語コミュニティ
  • Insights
  • IoT Apigee Link
  • BaaS/Usergrid
  • BaaS Transition/Migration
  • Apigee-127
  • New Customers
  • Explore
  • Topics
  • Questions
  • Articles
  • Ideas
  • Badges