Can I be sure that all incoming apikeys are 32 alphanumeric characters?

Not applicable

Sometimes we pass API keys to our backend servers rather than removing them at the Apigee level, so that we can do logging, correlation, etc.. For security and usability reasons, we always want to be sure our backends are acting upon valid input. This the incoming API key has to be validated on arrival

Can I always be sure that my client's API keys will contain 32 characters from the set [0-9,A-Z,a-z]?

2 10 791
10 REPLIES 10

No , I don't think so. The format of the API key in Apigee is is currently 32 characters from that set, but we haven't documented that behavior and there's no guarantee that it won't change. In fact we are considering making the flexible, and even now for on-premises customers they can supply their own limits for the size of the key, and there is also configurable support for a Xeger-based generator that would generate a key matching a particular regex.

So I think you cannot count on the format.

For logging and correlation, there is also a "messageid" context variable, that may be more suitable than the api key. The messageid is unique per request.

Thanks Dino. So what should I consider to be the format of a 'valid' API key?

May I ask you: what do you need to know this for? What are you really trying to do? I think for now, an API key is "an opaque string of characters".

One more thing I forgot to mention: with Edge, it is possible to "import" an API Key administratively. By which I mean, an Administrator could create a new credential with an API key of whatever form desired.

It's pretty simple: Edge connects to some of our backends with a single user ID for all developers using the API. However, we want to know which developer is connecting so that, if we want to debug an issue they're having, or identify someone who's misbehaving, we can do that from the backend easily. The messageid is not so useful - how can I find the developer corresponding to a messageid from the Edge Admin UI?

However, if for some reason the security between Apigee and the backend is compromised, we don't want the key passing mechanism to be a potential access point for variable injection. We want to validate the input as tightly as possible - with a min and max length for the key, and a defined valid character set.

In that case, why do you not send back the developer ID?

That information is available implicitly in the Edge request context, as soon as you validate an API key. The context variable is: developer.id .

If you want the developer name, or email, then you can use an AccessEntity policy to retrieve that information. Sending keys (which are supposed to be shared secrets, I think) seems like a less than optimal idea.

The API Key can change, for a single developer app, of course. Edge allows for more than one set of credentials for a single app. This is to allow key expiry and rotation. The app id and developer ID remain constant.

I understand that you want to assure some additional security between Edge and your backend. I think you will be relying on 2-way TLS, is that right? In which case, the transport ensures the security of the information.

If you feel the need to layer application-level or message-level security on top of the transport layer security, I'd say that just verifying a format of the data is not very strong. It would allow a hacker to substitute one valid apikey for another: they will both be valid!

A better approach might be to send a signature of the data - an HMAC using a key that is shared between Edge and the backend.

in other words send in headers:

X-Edge-Developer-id: context-variable(developer.id)

X-Edge-Hmac : HMAC(shared-key, concat(context-variable(developer.id), date))

...and your backend can verify the HMAC. You'd want to include a varying piece of information in the thing-to-be-signed, to prevent replays. The current date (epoch) would work, or a nonce. If you use the date, then you would need to allow for some skew between the times on the respective machines. Maybe 60s should be sufficient.

But this may be overkill, if you have 2-way transport-layer security.

OK - so having implemented this, I see it doesn't work. The developer ID adds an extra layer of complexity for no benefit. Every time you want to trace back, you need to look up the developer ID from the API key, which is not a super obvious thing to do and requires the user to have admin access to Edge. It's much easier to just trace with the API key. So really the question is - how can I guarantee the format of the API key?

Just seeing this now. I don't know what you mean by "requires the user to have admin access to Edge." Maybe you're missing the AccessEntity policy? I'm sorry about the trouble.

The AccessEntity policy can be included into any Apigee Edge proxy. Your proxy can retrieve the information about the developer associated to a key, by using a policy configuration like this:

<AccessEntity name="GetDeveloperProfile">
  <EntityType  value="developer"/>
  <EntityIdentifier ref="request.queryparam.apikey" 
        type="consumerkey"/> 
</AccessEntity>
 

If you pass the apikey in a place other than the queryparam named "apikey", then change the ref attribute in the EntityIdentifier as appropriate.

The result will be, a new variable populated into the context of the request. It will contain XML (sorry!) that you can then parse, again within the policy flow, to extract the particular details you want. There's no admin access needed to do the lookup.

The full XML for a Developer entity looks like this:

<Developer>
    <Apps>
        <App>weatherappx</App>
        <App>weatherapp</App>
    </Apps>
    <Email>ntesla@theramin.com</Email>
    <DeveloperId>4Y4xd0KRZ1wmHJqu</DeveloperId>
    <FirstName>Nikola</FirstName>
    <LastName>Tesla</LastName>
    <UserName>theramin</UserName>
    <OrganizationName>apigee-pm</OrganizationName>
    <Status>active</Status>
    <Attributes>
        <Attribute>
            <Name>project_type</Name>
            <Value>public</Value>
        </Attribute>
    </Attributes>
    <CreatedAt>1349797040634</CreatedAt>
    <CreatedBy>rsaha@apigee.com</CreatedBy>
    <LastModifiedAt>1349797040634</LastModifiedAt>
    <LastModifiedBy>rsaha@apigee.com</LastModifiedBy>
</Developer>
<br>

And then if you want to get the developerID or developer name or developer email, you can extract those fields with the appropriate ExtractVariables policy. For example:

<ExtractVariables name='EV-1'>
  <Source>AccessEntity.GetDeveloperProfile</Source>
  <XMLPayload>
    <Variable name='dev_email' type='string'>
      <XPath>/Developer/Email/text()</XPath>
    </Variable>
    <Variable name='dev_fname' type='string'>
      <XPath>/Developer/FirstName/text()</XPath>
    </Variable>
    <Variable name='dev_lname' type='string'>
      <XPath>/Developer/LastName/text()</XPath>
    </Variable>
  </XMLPayload>
</ExtractVariables><br>

The previous policy would extract the email, first name and last name of the developer from the XML profile retrieved by AccessEntity. Note: you need to specify, in the Source element, the name of the variable that holds the XML to extract FROM. In this case the name of the variable is the concatenation of "AccessEntity." , and the name of the AccessEntity policy. If you name your AccessEntity policy "AE-1", then the Source element here must be "AccessEntity.AE-1"

After this policy runs, you will have 3 new context variables containing simple strings, dev_email, dev_fname, dev_lname .

But, to answer your specific question, "how can I guarantee the format of the api key?" I think the general answer is "you cannot" for reasons I explained previously.

And I think there are special cases where you can rely on it being exactly 32 characters from the set [0-9,A-Z,a-z]. Those cases are:

- Apigee does not change the key format. (we have not changed it in years, but there's no guarantee!)

- you never import a key of arbitrary format.

It may be a situation you can live with. "Probably" the keys will be 32 characters from the set [0-9,A-Z,a-z].

Thanks @Dino, that's very comprehensive.

I guess I wasn't clear when I said the user, I meant the Amadeus developer who is trying to trace the call to find more info. The Access Entity policy doesn't really help them get the information they require to trace the call into their backend.

I think your last comment sums it up: there are special cases, that for now always apply. And what I'd really like is a way to bake in, or guarantee, the existing format in my ORG. Is that possible?

This not an answer to the original question, but the same question to serve a different purpose:

We need to concatenate the app_key with other values in a string & I would like to make sure that the character we use as a separator in the string is not used by the apigee app_key generator.

Is ":" safe? Maybe "/" or "|"?

Yes, by default the app keys are alphanumeric.