Managing API access rights: who gets to do what, and why?
Try asking this in your next meeting: which systems can currently reach our customer data? Usually there is a short silence, followed by "let me check that". Which is fair enough. Integrations get built the moment someone needs them, and after that almost nobody looks at them again.
That is how the classics appear. An accounting connection that can technically read every customer file while it only needs to pull invoices. A test account from 2023 that still works happily against production. An API key that ended up in a chat message once because it had to be done quickly. Integrations grow along the way: your webshop starts talking to the stock system, the CRM talks to your marketing tool, and an external developer adds a portal. Nothing breaks and no system complains. That is exactly why it stays that way for years.
Permissions are not a purely technical topic
An API is a door between two systems. What is allowed through that door is decided by permissions. That is partly security, but it is just as much process design: you determine what a supplier, a script or a colleague can do through it. An application can read data or write it back, and that difference matters more than it looks.
Overly broad permissions are the most common problem by far. A connection that only needs to read new orders gets full access to customers, products and settings, because at least then it is sorted. It works fine. Until the day that connection is abused or a bug writes in the wrong direction, and the damage is far bigger than the job that connection was hired to do.
Setting things too tight has a price too. A fulfilment partner who cannot push through an address change will call your service desk instead. That costs more time than the integration saves. So the answer is not "lock everything down to be safe", and it is not "open everything up to be safe" either. It is writing down, per connection, which action is needed and on which data.
This is why you cannot park the topic with development alone. The process owner knows whether an integration is still needed. Finance knows which data is sensitive. Operations knows what runs at night. Miss one of the three and every clean-up becomes guesswork.
Start with an overview you will actually maintain
Tightening permissions without knowing what exists is mostly guessing. Most companies do have a list of systems, but no current picture of integrations, accounts and keys. A spreadsheet from 2024 will not help you at three in the morning.
So keep it small, because otherwise it goes stale anyway. Per connection: which system provides the API, which application uses it, who owns it commercially, who owns it technically, what data goes across, and how it authenticates (API key, OAuth, service account or certificate). Six lines per connection is enough, and six lines is something you will keep up to date. An exhaustive document is not.
The test is simple. If a supplier calls to say a token expires tomorrow, you should know within minutes which process stops and who is allowed to decide. If you cannot, your overview is not finished yet.
Put a name on every connection
An administrator can replace a key, but cannot judge whether an integration still makes sense. So next to a technical owner, assign a business owner as well. That is the person who flags it when a contract ends, when a package is replaced or when a process changes shape.
Without that name you get the familiar stalemate: a connection has been running for four years, nobody knows exactly what for, and nobody dares switch it off. In the end it stays because turning it off feels risky, not because it is needed.
Grant as little as possible, as precisely as possible
The starting point is not complicated: a connection gets the permissions that match the agreed task and nothing else. It is called least privilege, but you do not need the term to apply it.
At the very least, separate reading, writing and deleting. Reading stock levels is not the same as changing them. Looking up a customer number is not the same as exporting the entire customer base including billing addresses. If the API supports scopes, pick them by hand. Ticking "all scopes" saves five seconds and buys you years of extra exposure.
Separate your environments too. Test, acceptance and production each get their own accounts and their own keys. That sounds obvious, but exactly when production is briefly unreachable and there is a deadline, that boundary stretches surprisingly easily. Agree on it in advance, so you do not have to have the discussion on a bad day.
The same goes for your own tooling. A customer service dashboard rarely needs admin rights. A reporting script does not need to create users. Attach permissions to roles rather than to individuals, and it stays workable when someone moves to another team.
Pick an authentication method that fits the connection
An API key can work perfectly well for a narrow server to server connection, as long as you store it safely and replace it periodically. Be honest with yourself here. If you already know that nobody will get around to rotating it, then a long lived key is a permanent key in practice. In that case, pick a method where expiry happens by itself.
When access happens on behalf of a user or a customer organisation, OAuth usually makes more sense. Consent is explicit and, more importantly, someone can withdraw it again without you having to hunt down a key somewhere.
For automated processes, such as a nightly sync, use a service account. Not a colleague's personal account. That goes wrong the day that person leaves, changes role or switches on two factor authentication, and suddenly a process nobody was thinking about grinds to a halt.
Short lived tokens limit the damage of a leak, but they do require that renewal is set up reliably. That is real work, and it is fair to weigh it. What is sensible depends on how sensitive the data is, what the platform supports and how much maintenance you can realistically carry. Convenience is allowed to count, as long as you say out loud what you are trading away for it.
Treat keys as company secrets
Keys, tokens and client secrets do not belong in source code, email, tickets or chat. A repository gets cloned, a ticket is often visible to more people than you think, and a chat message from 2022 is still sitting there.
Put secrets in a secret store and let applications fetch them only at runtime. Give developers their own test credentials for local work. And if something does get out, replace the key immediately. Deleting the line from a file solves nothing, because the history is still there and may already have been copied.
Without logging you are guessing
Getting permissions right is one thing. Knowing what happens afterwards is another. You want to be able to see which identity called an API, from which system, which action was performed and whether it succeeded. Without that, you notice unusual behaviour only when someone happens to bump into it.
You do not need to review every request, and you could not anyway. Do agree on which signals deserve a look: a run of failed attempts, an export ten times larger than usual, traffic at odd hours or from unfamiliar locations. What counts as odd differs per company. A webshop keeps humming on a Saturday evening, while a finance connection waking up at three in the morning genuinely raises a question.
That same logging helps with ordinary failures. When an order does not come through, you want to know quickly whether it is the permissions, an expired token, a new API version or simply an empty required field. Otherwise three suppliers politely point at each other while the orders sit still.
Make revoking part of the process
Access you can grant in ten minutes should be revocable in ten minutes. So include API access in your offboarding, for employees and for external parties. At the end of every project, check whether temporary accounts, test webhooks and old keys are genuinely gone rather than just unused.
Schedule a regular clean-up round as well. Quarterly works well for critical connections, while twice a year is fine for small, stable integrations. And do not only look at whether there is traffic. A connection can be technically healthy and still no longer desirable, for instance because the agreement with that party has changed.
Record changes briefly: who approved it, what was adjusted and why. Handy during an audit, but mostly useful for yourself. When an integration suddenly breaks after a release, one line in that log usually beats an hour of searching.
Agree on who manages what
Integrations quickly involve three or four parties: your own team, the software vendor, an agency and possibly a hosting company. At that point the key question is not technical but organisational. Who creates credentials? Who rotates them? Who gets the call about suspicious traffic? And who is allowed to change anything in production?
While things are calm, vague arrangements will carry you a long way. The moment there is pressure, every bit of ambiguity costs time straight away. That is why it helps to have development, hosting and management sitting together instead of spread across three parties. A good technical partner prefers to keep those under one roof. At LJPc we mostly see the difference in lead time: one point of contact usually saves the first two hours of searching during an incident.
Getting API permissions in order feels like tidying up without anything visibly improving. Yet it is exactly what makes the next integration easier, because you no longer have to guess what you are touching. Start with the integration that handles the most sensitive data or supports the most critical process. Once ownership, minimal permissions and logging are solid there, the rest is mostly repetition.