Skip to content
Preptima
hardScenarioDesignMidSeniorStaff

A customer's API token turns up in a public repository. What do you do in the next hour, and what in your token design decides how bad this is?

The damage is fixed before the leak by three earlier decisions: whether the token can be revoked and how fast that takes effect, how narrowly it was scoped, and whether your audit trail can attribute actions to that specific credential rather than only to the tenant.

6 min readUpdated 2026-07-29Target archetype: Big Tech, Enterprise Captive, Product Startup
Practice answering out loud

What the interviewer is scoring

  • Whether revocation is possible at all, and how long it takes to take effect for tokens already in circulation
  • Does the candidate bound the damage from the token's own scopes rather than assuming it could do everything
  • That detection is addressed and not only response, including how you would learn of misuse without being told
  • Whether the audit trail can attribute actions to one credential rather than only to the tenant
  • Can they state the cost of a stateless self-contained token at the exact moment you need to invalidate one

Answer

The first hour, in order

Revoke before you investigate. The instinct to establish the facts first is wrong here, because every minute the credential remains valid is a minute an automated scanner may be using it, and revocation is reversible in a way that exfiltration is not. Issue a replacement and tell the customer, in that order, so their integration has somewhere to go.

Then determine what the token could do, from its recorded scopes rather than from an assumption. This is why scopes exist: a credential that could only read invoices produces a very different incident from one that could create users. Establish when the secret was first published, which for a repository is usually recoverable from history, and treat everything from that moment as potentially compromised rather than only from when you noticed.

Next, query your access log for that specific credential across the whole exposure window, and classify what you find into the customer's own legitimate calls and anything else. Anything else means data was accessed, which converts this from a security event into a notification obligation with a legal deadline attached. If your logs cannot separate one token's activity from the tenant's other traffic, you cannot answer the question a regulator and the customer will both ask, and the honest answer becomes "we must assume everything in scope was read".

Finally, check whether the same secret is anywhere else. A token committed to a repository has very likely also reached a continuous integration log, a container image layer, a support ticket and someone's shell history, and revoking the one copy you were shown while the others remain valid is not containment.

Whether revocation works at all was decided long ago

Everything above assumes revocation is available and takes effect quickly. Whether it does is a consequence of how you chose to represent the token, and this is the trade-off the question is really testing.

An opaque token is a random string that means nothing by itself; the API looks it up in a store to find who it belongs to and what it may do. Revocation is a single row update and is effective immediately for every subsequent request. The cost is a lookup on the hot path of every call, which is a real availability and latency dependency and the reason people move away from it.

A self-contained signed token carries its claims in the token itself, and the API verifies a signature rather than consulting a store. There is no lookup, which scales beautifully, and the direct consequence is that there is nothing to change when you want to withdraw it. The token is valid until it expires because validity is a mathematical property of the bytes, not a fact in your database. Handing out a self-contained token with a long lifetime is therefore handing out an unstoppable credential, and the failure mode only becomes visible on the day you need to stop one.

The reconciliation is well established and worth stating as a design rather than as a compromise. Keep self-contained access tokens short-lived — minutes, not days — and pair them with a long-lived refresh credential that is opaque and therefore revocable. Revoking the refresh credential then bounds the damage to the remaining lifetime of the access token, and that lifetime is a number you chose. For the cases where minutes are still too long, maintain a deny list of revoked identifiers, checked on each request, and accept that you have reintroduced a lookup for exactly the population that needs one. The deny list only has to hold entries until their tokens would have expired anyway, so it stays small.

The number to actually state is your effective revocation latency, and people habitually understate it, because it is not the database write. It is the write plus the longest cache anywhere on the path: a gateway that caches validation decisions for a minute makes revocation take up to a minute, a per-node cache with a five-minute expiry makes it five, and a downstream service that accepted the token and is now holding a long-lived session may not re-check at all.

Scope is what turns a breach into an inconvenience

Since credentials leak eventually, the design question is not how to prevent it but how little a leaked one is worth. Three reductions do most of the work.

Grant capabilities rather than access. A token issued to a reporting integration should carry read permission on the two resources it reads, and nothing else, so a leak costs you a disclosure of data the customer already had rather than the ability to mutate their account. The pushback is always usability, and the answer is that scopes should be presented as templates matching real integration shapes rather than as a checklist of forty permissions, because a scope model nobody can navigate gets used by selecting everything.

Issue one credential per integration, never one per tenant. A shared tenant-wide key means every leak requires rotating something four systems depend on, so rotation becomes an outage and therefore gets deferred, which is how a compromised credential stays live for weeks. Per-integration credentials make revocation surgical and make the audit trail meaningful, because the log then says which integration acted rather than only which company.

Bind the token to something the holder must also possess. An address allowlist is coarse and defeats a large fraction of casual abuse, since a scanner running elsewhere cannot use the token at all. Mutual TLS or a proof-of-possession scheme is the stronger form: the request must be signed by a key the client holds, so the bearer token alone is insufficient and copying the string achieves nothing. RFC 9449 specifies one such mechanism for OAuth, and the general property to name is that a bearer credential is by definition usable by anyone who obtains it, so removing bearer semantics removes the entire value of stealing it.

Detection, because you will not always be told

This incident began with somebody noticing. Design for the version where nobody does.

The highest-value control is free: the major code-hosting platforms run secret scanning, and providers can register token formats so that a match is reported to them directly. That requires your tokens to be recognisable — a distinctive prefix and a checksum, so a scanner can identify the string as your credential with confidence and without false positives. Making your secrets easy to spot is counter-intuitive and it is unambiguously the right call, because the party you are helping is the scanner, not the attacker, who already knows what he has.

Behind that, watch the credential's own behaviour, since a stolen token is used differently from a legitimate one: a shift in source network for a machine credential that has called from one place for a year, a first-ever call to an endpoint the integration has never touched, or enumeration walking sequential identifiers. Per-credential rate limits earn their place here for a reason beyond capacity — they bound how much data a stolen token can extract before your response completes.

Rotation has to be possible before it is urgent

The final point, and the one that decides whether any of this works under pressure, is that a rotation path exercised for the first time during an incident is a rotation path that fails. Support two valid credentials per integration simultaneously, so the customer can introduce the new one, verify their traffic has moved, and retire the old one without a window where neither works. Publish the age of each credential in your dashboard and API so customers can see what they have. And expire tokens on a schedule by default, because a credential with no expiry accumulates copies for as long as it exists, and a routine rotation that happens every ninety days is a rehearsal for the day it is not routine.

Whether a leaked token is a bad afternoon or a breach notification is settled before the leak, by three things: that it can be revoked and how quickly that propagates through every cache on the path, how few operations it was ever permitted to perform, and whether your logs can say what that one credential did.

Likely follow-ups

  • Your tokens are signed and self-contained with a 24-hour lifetime and no revocation list. What can you do in the next five minutes?
  • How do you rotate a customer's credential when their integration has no mechanism for picking up a new one without downtime?
  • Which operations would you require a second factor or a separately signed request for, whatever the token says?
  • How do you scope tokens so that a leak cannot delete data, without forcing customers to manage ten of them?

Related questions

Further reading

api-tokensrevocationleast-privilegecredential-rotationaudit-logging