Update 10/23/2016: Interested in securing Android and iOS apps? Be sure to check out our guide to Securing Android Applications as well as our guide to Securing iOS Applications. And… If you want to build a REST API that your mobile apps can talk with, we’ve also got you covered.
Mobile API consumption is a topic that comes up frequently on both Stack Overflow and the Stormpath support channel. It’s a problem that has already been solved, but requires a lot of prerequisite knowledge and sufficient understanding in order to implement properly.
This post will walk you through everything you need to know to properly secure a REST API for consumption on mobile devices, whether you’re building a mobile app that needs to access a REST API, or writing a REST API and planning to have developers write mobile apps that work with your API service.
My goal is to not only explain how to properly secure your REST API for mobile developers, but to also explain how the entire exchange of credentials works from start to finish, how to recover from security breaches, and much more.
Before we dive into how to properly secure your REST API for mobile developers — let’s first discuss what makes mobile authentication different from traditional API authentication in the first place!
The most basic form of API authentication is typically known as HTTP Basic Authentication.
The way it works is pretty simple for both the people writing API services, and the developers that consume them:
- A developer is given an API key (typically an ID and Secret). This API key usually looks something like this:
- A developer is responsible for storing this API key in a secure place on their server, in a place that nobody else can access it.
- The developer makes API requests to the API service by putting the API key he was given into the HTTP Authorization header along with the word
Basic(which is used by the API server to properly decode the authorization credentials). Here’s how a developer might specify his API key when authenticating to an API service via the command line tool
$ curl --user 3bb743bbd45d4eb8ae31e16b9f83c9ba:ffb7d6369eb84580ad2e52ca3fc06c9d https://api.example.com/v1/test
cURL tool will take the API credentials, base64 encode them, and create an HTTP Authorization header that looks like this:
The API server will then reverse this process. When it finds the HTTP Authorization header, it will base64 decode the result, grab the API key ID and Secret, then validate these tokens before allowing the request to continue being processed.
HTTP Basic Authentication is great because it’s simple. A developer can request an API key and easily authenticate to the API service using this key.
What makes HTTP Basic Authentication a bad option for mobile apps is that you need to actually store the API key securely in order for things to work. In addition to this, HTTP Basic Authentication requires that your raw API keys be sent over the wire for every request, thereby increasing the chance of exploitation in the long run (the less you use your credentials, the better).
In most cases, this is impractical as there’s no way to safely embed your API keys into a mobile app that is distributed to many users.
For instance, if you build a mobile app with your API keys embedded inside of it, a savvy user could reverse engineer your app, exposing this API key, and abusing your service.
This is why HTTP Basic Authentication is not optimal in untrusted environments, like web browsers and mobile applications.
NOTE: Like all authentication protocols, HTTP Basic Authentication must be used over SSL at all times.
Which brings us to our next section…
You’ve probably heard of OAuth before, and the debate about what it is and is not good for. Let’s be clear: OAuth2 is an excellent protocol for securing API services from untrusted devices, and it provides a nice way to authenticate mobile users via what is called token authentication.
Here’s how OAuth2 token authentication works from a user perspective (OAuth2 calls this the password grant flow):
- A user opens up your mobile app and is prompted for their username or email and password.
- You send a POST request from your mobile app to your API service with the user’s username or email and password data included (OVER SSL!).
- You validate the user credentials, and create an access token for the user that expires after a certain amount of time.
- You store this access token on the mobile device, treating it like an API key which lets you access your API service.
- Once the access token expires and no longer works, you re-prompt the user for their username or email and passwordU.
What makes OAuth2 great for securing APIs is that it doesn’t require you to store API keys in an unsafe environment. Instead, it will generate access tokens that can be stored in an untrusted environment temporarily.
This is great because even if an attacker somehow manages to get a hold of your temporary access token, it will expire! This reduces damage potential (we’ll cover this in more depth in our next article).
Now, when your API service generates an Oauth2 access token that your mobile app needs, of course you’ll need to store this in your mobile app somewhere.
Well, there are different places this token should be stored depending on what platform you’re developing against. If you’re writing an Android app, for instance, you’ll want to store all access tokens in SharedPreferences (here’s the API docs you need to make it work). If you’re an iOS developer, you will want to store your access tokens in the Keychain.
If you still have questions, the following two StackOverflow posts will be very useful — they explain not only how you should store access tokens a specific way, but why as well:
It’s all starting to come together now, right? Great!
You should now have a high level of understanding in regards to how OAuth2 can help you, why you should use it, and roughly how it works.
Which brings us to the next section…
Let’s talk about access tokens for a little bit. What the heck are they, anyway? Are they randomly generated numbers? Are they uuids? Are they something else? AND WHY?!
Here’s the short answer: an access token can technically be anything you want:
- A random number
- A random string
- A UUID
As long as you can:
- Issue it to a client,
- Verify that it was created by you (using a strong signature),
- And assign it an expiration time…
BUT… With that said, there are some conventions you’ll probably want to follow.
Instead of handling all this stuff yourself, you can instead create an access token that’s a JWT (JSON Web Token). It’s a relatively new specification that allows you to generate access tokens that:
- Can be issues to clients.
- Can be verified as being created by you (more on this later).
- Can expire automatically at a specific time.
- Can hold variable JSON information.
- Can reduce the amount of API calls to your service by allowing users to validate / verify their API credentials LOCALLY, without querying your service!
JWTs also look like a randomly generated string: so you can always store them as strings when using them. This makes them really convenient to use in place of a traditional access token as they’re basically the same thing, except with way more benefits.
JWTs are almost always cryptographically signed. The way they work is like so:
- You store a secure random string somewhere on your API server. This should ideally just be a long random string (40 characters or so is fine).
- When you create a new JWT, you’ll pass this random string into your JWT library to sign the token, along with any JSON data you want to store: a user account ID, an email address, what permissions this user has, etc.
- This token will be generated, and it’ll look something like this:
header.claims.signature— where header, claims, and signature are just long base64 encoded strings. This isn’t really important to know though.
- You give this token to your user: likely an API client (eg: your mobile app).
Now, from the mobile client, you can view whatever is stored in the JWT. So if I have a JWT, I can easily check to see what JSON data is inside it. Usually it’ll be something like:
"scope": "can-read can-write"
Now, this is a 100% fictional example, of course, but you get the idea: if I have a copy of this JWT token, I can see the JSON data above, yey!
But I can also verify that it is still valid because the JWT spec supports expiring tokens automatically. So when you’re using your JWT library in whatever language you’re writing, you’ll be able to verify that the JWT you have is valid and hasn’t yet expired (cool).
This means that if you use a JWT to access an API service, you’ll be able to tell whether or not your API call will work by simply validating the JWT! No API call required!
Now, once you’ve got a valid JWT, you can also do cool stuff with it on the server-side.
Let’s say you’ve given out a JWT to a mobile app that contains the following data:
"scope": "can-read can-write"
But let’s say some malicious program on the mobile app is able to modify your JWT so that it says:
"scope": "can-read can-write can-delete"
See how I added in the can-delete permission there? What will happen if this modified token is sent to our API server? Will it work? Will our server accept this modified JWT?
When your API service receives this JWT and validates it, it’ll do a few things:
- It’ll check the token to make sure it wasn’t tampered with. It does this by using the secret randomly generated string that only the server knows. If the JWT was modified at all, this check will fail, and you’ll know someone is trying to do something nasty.
- It’ll also check the expires time of this JWT to make sure it’s actually valid. So if you assigned a JWT a long time ago that has long since expired, you’ll know that your client is trying to use an old token — so you can just reject their API request.
This is nice functionality, as it makes handling verification / expiration / security a lot simpler.
The only thing you need to keep in mind when working with JWTs is this: you should only store stuff you don’t mind exposing publicly.
As long as you follow the rule above, you really can’t go wrong with using JWTs.
The two pieces of information you’ll typically store inside of a JWT are:
- A user account’s unique ID of some sort. This way you can look this user up from your user database when you receive this JWT for authentication.
- A user’s permissions: what they can and can’t do. If you’re building a simple API service where all users are the same, this may not be necessary. But this way, users won’t need to hit your API to figure out what they can do all the time: instead, they can just look at their JWT.
So, that just about sums up JWTs. Hopefully, you now know why you should be using them as your OAuth access tokens — they provide:
- A nice way to validate tokens.
- A nice way to pass publicly-viewable information to a client.
- A simple interface for developers to work with.
- Built-in expiration.
Now, moving on — let’s talk about how this all works together…
In this section, we’re going to get into the nitty gritty and cover the entire flow from start to finish, with all the low-level technical details you need to build a secure API service that can be securely consumed from a mobile device.
Ready? Let’s do this.
First off, here’s how things will look when we’re done. You’ll notice each image has a little picture next to it. That’s because I’m going to explain each step in detail below.
So, take a look at that image above, and then follow along.
The user opens the app! Next!
Since we’re going to be using the OAuth2 password grant type scheme to authenticate users against our API service, your app needs to ask the user for their username or email and password.
Almost all mobile apps ask for this nowadays, so users are used to typing their information in.
Next, the user enters their credentials into your app. Bam. Done. Next!
This is where the initial OAuth2 flow begins. What you’ll be doing is essentially making a simple HTTP POST request from your mobile app to your API service.
Here’s a command line POST request example using cURL:
$ curl --form 'grant_type=password&username=USERNAMEOREMAIL&password=PASSWORD' https://api.example.com/v1/oauth
What we’re doing here is POST’ing the username or email and password to our API service using the OAuth2 password grant type: (there are several grant types, but this is the one we’ll be talking about here as it’s the only relevant one when discussing building your own mobile-accessible API).
NOTE: See how we’re sending the body of our POST request as form content? That is,
application/www-x-form-urlencoded? This is what the OAuth2 spec wants =)
What happens next is that your API service retrieves the incoming username or email and password data and validates the user’s credentials.
This step is very platform specific, but typically works like so:
- You retrieve the user account from your database by username or email.
- You compare the password hash from your database to the password received from the incoming API request. NOTE: Hopefully you store your passwords with bcrypt!
- If the credentials are valid (the user exists, and the password matches), then you can move onto the next step. If not, you’ll return an error response to the app, letting it know that either the username or email and password are invalid.
Now that you’ve authenticated the app’s OAuth2 request, you need to generate an access token for the app. To do this, you’ll use a JWT library to generate a useful access token, then return it to the app.
Here’s how you’ll do it:
- Using whatever JWT library is available for your language, you’ll create a JWT that includes JSON data which holds the user ID (from your database, typically), all user permissions (if you have any), and any other data you need the app to immediately access.
- Once you’ve generated a JWT, you’ll return a JSON response to the app that looks something like this:
As you can see above, our JSON response contains 3 fields. The first field
access_token, is the actual OAuth2 access token that the mobile app will be using from this point forward in order to make authenticated API requests.
The second field,
token_type, simply tells the mobile app what type of access token we’re providing — in this case, we’re providing an OAuth2 Bearer token. I’ll talk about this more later on.
Lastly, the third field provided is the
expires_in field. This is basically the number of seconds for which the supplied access token is valid.
In the example above, what we’re saying is that we’re giving this mobile app an access token which can be used to access our private API for up to 1 hour — no more. After 1 hour (3600 seconds) this access token will expire, and any future API calls we make using that access token will fail.
On the mobile app side of things, you’ll retrieve this JSON response, parse out the access token that was provided by the API server, and then store it locally in a secure location. On Android, this means SharedPreferences, on iOS, this means Keychain.
Now that you’ve got an access token securely stored on the mobile device, you can use it for making all subsequent API requests to your API server.
Not bad, right?
All that’s left to do now is to make secure API requests from your mobile app to your API service. The way you do this is simple.
In the last step, your mobile app was given an OAuth2 access token, which it then stored locally on the device.
In order to successfully make API requests using this token, you’ll need to create an HTTP Authorization header that uses this token to identify your user.
To do this, what you’ll do is insert your access token along with the word
Bearer into the HTTP Authorization header. Here’s how this might look using
$ curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJEUExSSTVUTEVNMjFTQzNER0xHUjBJOFpYIiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvNWpvQVVKdFZONHNkT3dUVVJEc0VDNSIsImlhdCI6MTQwNjY1OTkxMCwiZXhwIjoxNDA2NjYzNTEwLCJzY29wZSI6IiJ9.ypDMDMMCRCtDhWPMMc9l_Q-O-rj5LATalHYa3droYkY" https://api.example.com/v1/test
In the end, your Authorization header will look like this:
When your API service receives the HTTP request, what it will do is this:
- Inspect the HTTP Authorization header value, and see that it starts with the word
- Next, it’ll grab the following string value, referring to this as the access token.
- It’ll then validate this access token (JWT) using a JWT library. This step ensures the token is valid, untampered with, and not yet expired.
- It’ll then retrieve the user’s ID and permissions out of the token (permissions are optional, of course).
- It’ll then retrieve the user account from the user database.
- Lastly, it will ensure that what the user is trying to do is allowed, eg: the user must be allowed to do what they’re trying to do. After this is done, the API server will simply process the API request and return the result
Nothing anything familiar about this flow? You should! It’s almost the exact same way HTTP Basic Authentication works, with one main difference in execution: the HTTP Authorization header is slightly different (
This is the end of the “How it All Works” section. next article, we’ll talk about all the other things you need to know about managing API authentication on mobile devices.
As this is a high-level article meant to illustrate how to properly write an API service that can be consumed from mobile devices, I’m not going to get into language specific implementation details here — however, I do want to cover something I consider to be very important.
If you’re planning on writing your own API service like the ones discussed in this article, you’ll want to write as little of the actual security code as possible. While I’ve done my best to summarize exactly what needs to be done in each step in the process, actual implementation details can be quite a bit more complex.
It’s usually a good idea to find a popular OAuth2 library for your favorite programming language or framework, and use that to help offload some of the burden of writing this sort of thing yourself.
Lastly, if you really want to simplify things, you might want to sign up for our service: Stormpath. Stormpath is an API service that stores your user accounts securely, manages API keys, handles OAuth2 flows, and also provides tons of convenience methods / functions for working with user data, doing social login, and a variety of other things.
Stormpath is also totally, 100% free to use. You can start using it RIGHT NOW in your applications, and BAM, things will just work. We only charge you for real projects — feel free to deploy as many side projects as you’d like on our platform for no cost =)
Hopefully this article has helped you figure out the best way to handle API authentication for your mobile devices. If you have any questions (this stuff can be confusing), feel free to email us directly!