Skip to content
Expert Guide Series

Authentication vs Authorisation API Security Mistakes

A product can verify exactly who you are and still hand you access to things you should never see. Those two failures look similar from the outside, and they carry very different causes, but they share one origin: they were not separated clearly enough at the specification stage. We have seen this play out on real products, and the pattern is consistent. The security decisions that should have been made before a single line of code was written end up being made under pressure, mid-build, by developers who are solving a design problem with engineering effort.

Retrofitting compliance and access controls after launch costs far more than getting them right at specification.

The distinction between authentication and authorisation is not subtle. One asks who you are. The other asks what you are allowed to do. But in the rush to define features and get to build, the two get folded together into a vague concept called "security", and that is where the problems begin. On a peer-to-peer currency exchange product we worked on, where users could swap leftover foreign currency with other travellers at interbank rates, we built the core transfer mechanism well. What we did not factor in early enough was the authorisation logic around how many transfers any two parties could make, and what that absence would look like to a regulator. Apple flagged the product as a potential vehicle for money laundering because the transfer capability was effectively unlimited. We had to retrofit several layers of compliance: stricter KYC checks, enhanced transfer security, and hard caps on transfer volume between parties.

That experience shaped how we think about security architecture on every product since. Not as a layer to add, but as a set of decisions to make before the first sprint begins.

Authentication and Authorisation: The Precise Distinction

Authentication is the process of confirming identity. When a user logs in with a password, scans a fingerprint, or presents a token, the system is asking one question: are you who you claim to be? A correct answer grants entry. The process stops there. What the user is permitted to do once inside is a separate question entirely, and that is where authorisation begins.

Authorisation governs access to resources. It defines which endpoints a user can call, which data they can read or write, and which actions are available to them based on their role or context. A user authenticated as a standard account holder on a property management platform and a user authenticated as a building administrator are both genuinely who they say they are. The difference between them is entirely in what each is authorised to access.

In API design, this separation matters at a structural level. An API that authenticates every request but applies authorisation checks inconsistently will pass a basic security audit and still leak privileged data. An API that conflates the two will often protect certain endpoints robustly while leaving others entirely open, because the developer assumed that being logged in was sufficient proof of permission.

Concept Question it answers Typical mechanism Failure mode
Authentication Who are you? Password, token, biometric Identity spoofing, credential theft
Authorisation What can you do? Roles, scopes, policies Privilege escalation, data leakage

Keeping them distinct in your specification forces the right conversations early. Who are the user types? What does each role actually need? Which endpoints carry sensitive data that should never be exposed to a standard user? These are design questions, and they want answers before build begins.

Why the Two Are So Often Conflated

Part of the reason these two concepts get muddled is linguistic. In everyday conversation, "can you access this?" blurs identity and permission into one. Developers and product managers often carry that blur into specifications, writing requirements like "only logged-in users can view order history" without ever defining what types of logged-in users exist or whether all of them should see all orders.

There is also a sequence problem. Authentication is visible and testable early. A login screen exists. A user either gets in or they do not. Authorisation is harder to see and easier to defer, because the consequences only appear when a user with the wrong role tries to do something they should not. That moment often does not arrive until testing, or worse, after launch.

The frameworks used to build APIs do not always help. Many will wire up token-based authentication as a default, making it feel like security is handled. The developer sees a 401 response when a user is not logged in and assumes the surface is protected. What does not surface automatically is the absence of a check on what that authenticated user is permitted to do once their token is valid.

On the production management product we built for the film industry, we encountered the inverse of this problem. Third-party platforms holding production documents turned out to be far more locked down than anticipated. We had expected API access and found instead that the systems were secured in ways that prevented any integration at all. We had to pivot to ingesting emails tied to specific roles within a production to process data indirectly. The security was real, but it had been designed without any consideration of how external products might need to interact with it, which is itself a form of authorisation thinking done in isolation.

Start your app project the right way

We deliver the complete blueprint before a line of code is written. User research, psychology-driven design and full technical specifications. You choose who builds it.

See how we work Get started

No commitment

Common Authentication Mistakes in API Design

The most common authentication mistake is treating token presence as proof of legitimacy. A valid token confirms that a user was authenticated at some point. It does not confirm that the token has not been stolen, that it has not expired in a meaningful sense, or that the session it represents is still appropriate. APIs that accept any valid token without checking its context are vulnerable to replay attacks and credential reuse.

A valid token confirms past authentication, not present legitimacy, and that gap is where credential attacks land.

A second mistake is storing API keys and secrets in places they should not be. According to Serverion, 61% of organisations have accidentally exposed secrets such as API keys in public repositories. That figure reflects a specification failure as much as a developer error. If the handling of credentials is not defined explicitly in the specification, each developer will make their own decision about where to put them.

Define token expiry, rotation policy, and credential storage requirements in the specification, before build begins. Leaving these to developer judgement produces inconsistent implementations across a codebase.

A third mistake is weak or absent rate limiting on authentication endpoints. Login endpoints, password reset flows, and token refresh routes are all high-value targets. An API that does not limit repeated attempts against these endpoints is open to credential stuffing at scale. Shopify reduced credential stuffing attacks by 82% by implementing adaptive rate limiting that analysed request behaviour, according to Serverion. That kind of protection requires a deliberate design decision, not an afterthought.

On the peer-to-peer currency exchange product, we had implemented authentication correctly from the start. Users were who they said they were. The gap was in what authenticated users were permitted to do, and how much. Those are connected problems, but they demand separate thinking.

Common Authorisation Mistakes in API Design

The most damaging authorisation mistake is object-level access control that relies on the client to enforce boundaries. An API endpoint that accepts a resource ID and returns the associated record without checking whether the requesting user is entitled to that record is a broken object-level authorisation flaw. A user who knows or can guess another user's ID can request their data directly. The authentication layer sees a valid token and passes the request through. The authorisation layer never runs.

A second mistake is role definitions that were never properly designed. On the alcohol buying and selling platform we worked on, we had already started building the mobile product when we discovered we could not implement the planned API layer. The client's existing web application had been built by another developer in a way that made it too complex to expose cleanly via an API. We ended up embedding web elements from the existing site directly into the mobile product instead. That restriction cost approximately 20% uplift in work across the entire project. Because the client wanted to keep the budget fixed, we dropped features towards the end to compensate. The roles and access model had never been specified clearly for the API context, and the cost of that showed up in every subsequent decision.

A third mistake is over-provisioning roles out of convenience. According to Tech Prescient, most organisations discover they maintain 40 to 60% more roles than required, many being temporary roles that became permanent or were created by copying user rights without checking actual access requirements. That kind of drift starts at the specification stage, when roles are defined loosely and no one is accountable for auditing them later.

Map every user role to a specific list of permitted endpoints and data fields before build begins. Any endpoint not explicitly permitted for a role should be denied by default, and that default should be written into the specification.

When Access Control Logic Is Left to the Build Phase

When access control is not defined at the specification stage, it gets defined by whoever writes the code first. That is rarely the right person to make those decisions, and it produces inconsistent enforcement across an API surface. One developer will check roles before returning data. Another will assume the route is only accessible to the right users because of how the front end is built, without applying any server-side check at all.

We saw a version of this on a bootstrapped social football platform. Scope kept expanding, driven by a team member who was requesting design changes without considering development impact. Budget became critically strained midway through the project. We paused Android development and reallocated all remaining budget to the iOS product. The client launched iOS-only, reaching roughly half the potential market. The target audience skewed younger and disproportionately towards Android, which meant day-one adoption was significantly lower than it should have been. Post-launch, the client had to introduce advertising and abandon their subscription model because they lacked the user base to make subscriptions viable.

That project did not have a specific access control failure, but it illustrates the same underlying dynamic: decisions that belong at the specification stage, made under build-phase pressure, with consequences that outlast the project. Access control logic is particularly vulnerable to this because it is invisible until something goes wrong.

The developer building under time and budget pressure will naturally look for the fastest path. If the specification does not say what the authorisation rules are, the developer will make a judgement call. Some of those calls will be fine. Some will leave endpoints unprotected in ways that are not obvious from a standard code review.

The Real Cost of Retrofitting Security

Retrofitting authentication and authorisation after a product is built is expensive in ways that compound. The first cost is engineering time. Every endpoint needs to be revisited, the access logic needs to be defined retrospectively, and the new checks need to be tested without breaking existing functionality. On the currency exchange product, retrofitting AML compliance meant going back through the transfer logic, adding KYC checks, and implementing transfer limits. Each of those changes touched parts of the codebase that had been built on the assumption that they would not need to change.

The second cost is architectural. When authorisation is bolted on after the fact, it often sits in the wrong place. Checks that should happen at the data layer end up in middleware. Middleware checks that should be granular end up being coarse, because granular checks require understanding the data model in detail, and that understanding was not captured at the time. The result is a security layer that looks complete but has gaps at the seams.

The third cost is trust. A product that reaches users or partners with security failures, even briefly, carries reputational damage that engineering effort cannot fully repair. Apple's rejection of the currency exchange product was not a minor setback. It required a significant rebuild before the product could return to review. That delay had real consequences for the client's timeline and budget.

The Verizon 2024 Data Breach Investigations Report found that 76% of data breaches involved compromised credentials. That figure covers credentials that were stolen, reused, and exploited through APIs and mobile apps that did not apply sufficient authorisation controls. The cost of those breaches exceeds the cost of any specification-stage security investment by a wide margin.

Why These Decisions Belong in the Specification Stage

Security decisions belong at the specification stage because they shape the architecture. An API built around a clear role model, with defined scopes per endpoint and explicit access policies, is structured differently from one where those decisions were deferred. The data models, the endpoint design, the token structure, and the error handling all reflect the access control requirements. When those requirements are not known at the start, the architecture accommodates them as constraints rather than as design principles, and constraints cost more to accommodate than principles.

On the film industry document portal, we made accessibility an active design priority from the start because the product would be used by many different types of people in a fast-paced environment. The design was large-scale and built around reaching information quickly, because that was written into what the product needed to do. Accessibility as a specification-stage requirement shaped the entire design direction. Security works the same way. Define it early and it shapes good architecture. Define it late and it requires rework.

The specification stage is also the right time to ask the user-type questions that authorisation depends on. Who are the user roles? What does each role genuinely need to do? Which actions carry risk if performed by the wrong user? These questions surface edge cases, expose gaps in the product thinking, and produce requirements that developers can implement consistently. Without them, every developer answers the same questions independently and produces different answers.

Run a dedicated authorisation mapping session during specification. List every user role, every endpoint, and every data object. Mark permitted access explicitly. Any gap in that matrix is a specification gap, and it will become a security gap unless someone fills it before build begins.

How Specification-Stage Security Gaps Compound During Development

A security gap in the specification does not stay the same size through development. It grows. Each sprint that builds on an unresolved access control question adds more code that assumes the gap does not exist. By the time a security review happens, the assumption is baked into dozens of functions, and unwinding it requires touching each one.

We saw this with the anonymous messaging app we worked on. As we got deeper into the project and began examining the safety concerns that anonymous messaging inherently creates, we added in-product reporting features to allow users to escalate concerns about inappropriate messages to the admin team. We also needed to resolve a tension between GDPR, which gives users the right to have their data removed, and the legal requirement to retain data in case of criminal investigation. We implemented a data retention policy of around six months, so that if a user deleted their account after sending harmful messages, the data would still be available to investigators for a meaningful window.

Both of those decisions should have been in the specification. They were not, and so they arrived mid-project as engineering problems rather than design decisions. The reporting feature required changes to the data model. The retention policy required changes to how deletions were handled. Those changes had to be tested against all the existing functionality that had been built without them in mind. The later a security requirement arrives, the more it disturbs what is already built.

  1. A gap in the specification creates an implicit assumption in the code.
  2. Each subsequent sprint builds on that assumption without questioning it.
  3. A late-stage security requirement must then be retrofitted across every layer that carried the assumption.
  4. Testing the retrofit touches all existing functionality, multiplying the cost.
  5. Time and budget pressure at the end of a project mean that some of the retrofit is incomplete.

Getting Authentication and Authorisation Right Before Build Begins

The starting point is a clear user-type map. Every distinct type of user the product will serve needs to be named, described, and given an explicit list of what they are and are not permitted to do. Not a rough outline. A list specific enough that a developer can implement it without making judgement calls. If the specification says "admins have elevated access", it has said nothing useful. If it says "admins can read and modify all user records, create and archive accounts, and access the audit log, and no other role can do any of those things", it has said something a developer can build.

The second step is endpoint-level authorisation mapping. Every API endpoint should have a defined set of permitted roles. Any role not listed should receive a 403 response by default. This needs to be written into the specification, not left to the developer to infer from context. The document becomes a contract that any developer on the team can implement consistently.

The third step is thinking about token design. What claims does a token carry? Does it include the user's role? Does it include the scope of permitted actions? A token that carries only an identity provides authentication. A token that carries role and scope provides the foundation for authorisation. That design decision belongs at the specification stage because it affects how every endpoint in the API validates requests.

  • Define every user role with an explicit permission list before build begins.
  • Map each API endpoint to its permitted roles in the specification document.
  • Design token claims to carry the information authorisation checks will need.
  • Set denial as the default: any access not explicitly permitted is denied.
  • Plan for a security review against the specification before launch, not after.

On the currency exchange product, a specification-stage authorisation mapping would have surfaced the transfer volume question before build began. The question "how many transfers can two parties make with each other?" is a product question as much as a compliance one, and it has a design answer. Asking it early means the answer is in the architecture. Asking it after launch means the architecture has to change.

Conclusion

Authentication and authorisation are separate problems. They require separate thinking, separate design decisions, and separate implementation. Treating them as one concept called "security" is how products end up with robust login flows and unprotected data endpoints sitting side by side in the same codebase.

The work of getting them right happens before build begins. The user-type mapping, the endpoint access matrix, the token design, the default-deny policy. These are product decisions that belong in the specification, made by people who understand both the product's purpose and the risks its architecture creates.

We learned that on the currency exchange product. We built the authentication layer correctly and deferred the authorisation questions, and the authorisation questions came back as a compliance rejection that required significant rework. The engineering cost of that retrofit was real. The timeline cost was real. Both were avoidable with the right conversations at the right stage.

The products that avoid these failures are the ones where the security thinking happened early enough to shape the architecture rather than fight it. That means treating specification-stage security as a non-negotiable part of the design process, not as something to address when the build is done and the obvious gaps appear.

If you are building an API-driven product and want to get the authentication and authorisation model right before development begins, let's talk about your API security specification.

Frequently Asked Questions

What is the difference between authentication and authorisation?

Authentication confirms who a user is, typically through a password, token, or biometric check. Authorisation is a separate process that determines what that verified user is actually permitted to do once they have gained access.

Why are authentication and authorisation so often confused?

In the rush to define features and move to build, the two concepts tend to get folded together under a vague idea of 'security'. This means the precise decisions about identity and access are never clearly separated, which creates gaps that only become visible later.

What goes wrong when authorisation is not designed early enough?

Authorisation logic that is added mid-build or after launch is often inconsistent, leaving some endpoints protected and others entirely open. The article gives a real example where missing transfer limits on a currency exchange product led to it being flagged as a potential vehicle for money laundering.

Can a product pass a security audit and still leak privileged data?

Yes. An API that authenticates every request but applies authorisation checks inconsistently can pass a basic audit while still exposing data it should not. Authentication and authorisation must both be applied correctly and independently to provide genuine protection.

What does retrofitting compliance and access controls actually involve?

In the example described, retrofitting meant adding stricter KYC checks, enhanced transfer security, and hard caps on transfer volume between parties. This work was significantly more costly and disruptive than it would have been if those controls had been specified before development began.

What is privilege escalation and why does it matter?

Privilege escalation is the failure mode associated with poor authorisation, where a user gains access to actions or data beyond what their role permits. It matters because it can expose sensitive information or allow users to perform actions that should be restricted to administrators or other elevated roles.

When should security architecture decisions be made in a product build?

The article is clear that security decisions should be made before the first sprint begins, not under pressure during development. Treating security as a set of upfront design decisions rather than a layer to add later produces far more reliable and auditable products.

How does separating authentication and authorisation in a specification help a product team?

It forces the right conversations early, such as identifying all user types, defining what each role genuinely needs, and flagging which endpoints carry sensitive data. Those conversations are much cheaper to have on paper than they are to resolve in code after launch.