The term “API” is tricky. It stands for application programming interface, but a lot of people seem to think it means “all powerful incantation.” You always see decision makers sigh in relief when they find out a product they’re looking at has an API; they’re not sure what it means, but they know their developers will be able to do magic with it.
The trouble is that an API isn’t a single thing. It’s the classic elephant where blind men each get hold of a different part of the elephant… “It’s a snake!” “It’s a tree trunk!” “It’s a wall!” To front-end developers, it’s a collection of resources. To a SysOps engineer, it’s a firewall. To an engineer, it’s an abstraction. And to an information security officer, it’s a big mess.
Each step of consuming, exposing, building, and maintaining the API has very different needs, because every step is a very different animal. To that end, I want to run through the different areas of API usage, development, and management.
The API Contract
A contract is an agreement, regardless of the technology or the tools. Over the years, I’ve refined my own API style guide, and while there are lots of “right” ways to build an API, the wrong way is to build an API with inconsistent rules, blanket security, and a fractured series of endpoints.
The contract not only defines collections and resources and responses, but it also defines the rules of engagement. What are the authorization rules? How do you get access, and when you do, what access do you get? The contract should define what to do when you’re authorized to the API, but maybe not to a specific resource.
You can think of it as terms of service — it’s what we understand and what we should expect. Part of an API contract is firm directives, like telling you that you will not be granted access if you do something wrong (like bringing a knife through airport security). Some of the contract is just advice, like expected latency — so get to the airport with enough time to get through security.
Your API security strategy is a combination of the application AND the user, therefore that consumer is a compound rule. If the app is able to look at /people/*, but the user is only allowed to look at /people/bissell, then this key is only going to support /people/bissell.
Those rules should be easy for the developer to understand, and should be woven into the security of your API at every level. That way, if an app’s keys are exposed, they’re still useless unless someone logs in. And then the only thing that gets exposed is one user’s information.
The token is like a plane ticket — the API contract defines what class of seat you get, and the ticket agent assigns you a time, a plane, and a seat. That ticket is only good for that one thing. There may also be huge, byzantine rules behind how you got that seat, like you booked it through a partner, so you get X, but I work on corporate agreement, so I get Y. Regardless, the ticket is very clear: time, plane, and seat.
When we’re talking about security and identity, we need to separate the API from the services — just like airport security isn’t your flight, the API gateway isn’t your API service.
The security gate at the airport makes sure you’re allowed into the terminal…but it doesn’t make sure you get on the right plane. Your API gateway is kind of like that — it checks the credentials, and sort of sums up if someone looks a bit suspicious or not, but ultimately, once the person has passed the checkpoint, whatever they do is out of the gateway’s hands.
Mind you, your API gateway is still very important. It needs to verify all of your security credentials or you don’t get in. It can regulate how many requests are coming in. It deflects baddies at the edge, so the protected resources don’t have to think as much about random traffic.
If the API gateway is like airport security, then the actual services are like the airplanes themselves. You board the plane (the collection) and you have a specific seat assignment (the resource). You need a ticket for THAT seat on THAT flight at THAT time.
But say you have to change planes…Remember that long line out at the security gate? Your next flight is right next to the one you came in on…Imagine if you had to trudge all the way out of the terminal, past the gate, and then get right back into the same security gate to get to that flight that was only 50 feet from you.
Of course, you can’t just board any old plane just because you’re in the airport. Anything could go wrong if we just trusted that, once you got into the terminal, you could board any plane. This is why you have a second ticket. Maybe you brought it with you (which saves lots of time), or maybe the gate agent prints you a new one. But no matter what, you don’t have to go all the way back to the gate.
This is the same for the microservices. If you need to connect from one service to another, that transaction should have a new token – a token that is valid for that time – to access that specific service in a specific resource.
So, to sum up, your modern API ecosystem is like airfare:
- The API contract is defined by the airline to decide who gets to fly on what planes and in which seats.
- Consumers have to identify that they are, indeed, the people they say they are, and receive tickets (tokens) to travel.
- The API gateway lets those consumers into the terminal, but that’s the last they see of the consumers.
- The services are what we’re here for, but they’re protected. You need to have made it through security, and then you have to show your ticket again. And it has to be a different ticket for each plane you fly.
If you’re flying on a well-managed airline, it’s easy. If you’re flying on an airline that doesn’t quite have it all figured out…well, we know what kind of airline experience that’s like.
May your API always be First Class, and we hope you never lose your passport and ticket.