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.
Trouble is, 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 they are very different animals. 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 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 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 brining a knife through airport security). Some of the contract is just advice (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, and there may be huge, byzantine rules behind how you got that seat (like you booked through a partner so you get X but I work on corporate agreement so I get Y) but the ticket is very clear -- time, plane and seat.
When we’re talking 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, 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 to all 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, 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 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 what 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 gotten 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 you never lose your passport and ticket.