As an API provider, you open your restful back end to those you trust in the hopes of doing something useful, making a profit, or both. You’re quite careful about registering and authenticating your users, and you probably identify the app they are calling from, but is that enough to protect access and your revenue stream from malicious actors?
You want to know who is using your app, so you require some form of user authentication and authorization. If your client app is tightly coupled with your API back end, then you probably know and are authenticating the end users of your client. If the client is a 3rd party app calling your API, then the user might be the app owner acting as an intermediary for that app’s end users. For example, you could be providing a bike sharing API, and an independent local transportation app is booking one of your bikes on behalf of a local commuter.
In either case, using protocols such as OIDC and OAuth2, you authenticate the user’s identity directly or through an identity service and authorize access to your API through a signed access token.
In addition to identifying and authorizing users, you are going to want to identify which app is calling your API so you can monitor API usage and possibly enforce API usage policies on a per app basis.
Typically, you will have the app developer register the app with you and you will assign him an API key which acts as a unique app identifier. The API key is stored in the App and passed with every API call.
As your API gets more popular, you begin to see an increasing number of API calls without API keys. The API calls have provided valid user access tokens, so you have been letting them through, but users are starting to complain.
A significant number of users are asking for billing audits. They are claiming you are charging them for API calls they did not make. Additionally, some users are complaining that your service is sluggish. Your back-end costs are increasing, and you are noticing another trend where some users are making expensive search calls which tax your back end, but the percentage of those users who are following through with a monetizing API call, such as a full purchase, is dropping off substantially.
Reluctantly, you conclude that you are under attack. So you decide to implement some bot mitigation strategies and start dropping API calls with missing or unrecognized API keys, and you tighten up your rate limiting and behavioral analysis controls, hoping that you are not rejecting too many valid users making valid API calls.
Things improve briefly, but a key without a secret is kind of like requiring a user name without a password. That’s not much security, so you decide to add an API secret as well. You might require both key and secret to be passed with each call, or you might send the key but use the secret to sign each API call.
Either way, the API key and secret must be kept confidential. So you’re asking each app developer to hide the key and secret in their app through obfuscation or other app hardening techniques. You are also requiring them to use HTTPS/TLS and requesting that they pin their apps to your server’s certificates.
Unfortunately, your API security is now dependent, not on you, but on each app developer. Are you really comfortable with that?
In order to regain control of your API security, you must get that secret off of the app and make sure it is never directly exposed in your API calls.
So you take some inspiration from the OIDC/OAuth2 user authentication flows and apply some of their strategies to app authentication. Instead of embedding a static secret inside each app, you periodically challenge the app to ensure it is authentic. Once verified, you issue it an app authorization token that can be passed with each API call. Like a user access token, an app authorization token has a limited lifetime and is signed and verified using a secret which is not in the app nor sent through an API call.
You previously required an app developer to register his app at the beginning of development. Now you require him to register each app as it's released so that you can extract the app’s ‘DNA’ which you will use for authentication. Though each app still gets an API key for identification, you retain the API secret, and you’re back in control of your API security.
Each API call now carries a verifiable app authorization token. With this yes/no authentication model, you can fully exploit app identity and not worry about falsely rejecting valid API calls. You can use secure app identity to:
For your bike sharing app, for example, you might quote different rental rates to different app providers depending on their volume, or you might expose different bike inventory to different providers depending on real-time demand.
By authenticating instead of just identifying your apps, the quality of your traffic has increased. By countering the attacks, your traffic has become more predictable, so your back-end costs are under control, users are no longer complaining about sluggish response times, and you are not losing revenue through unauthorized API usage.
No longer as dependent on app developers to implement API protections, you can focus on evolving your API security to meet the next set of challenges that are always, always coming.