Skip to main content

Command Palette

Search for a command to run...

Why Concealing IDs in URLs Isn't Safe (Vue.js + FastAPI)

Introduction

Published
4 min read
Why Concealing IDs in URLs Isn't Safe (Vue.js + FastAPI)
S

Software Developer I build modern SaaS tools with Vue.js & FastAPI · Sharing tutorials, dev logs, and business insights for solo devs & makers. Building in public.

When building web applications, especially SPAs with frameworks like Vue.js, it’s very common to expose resource identifiers in URLs:

/offers/32

At some point, many developers feel uncomfortable with this and try to hide or obfuscate IDs on the frontend, thinking it improves security.

I did the same.

In this article, I’ll explain why hiding IDs in frontend URLs is not real security, what risks it introduces, and how to handle this problem properly using FastAPI, UUIDs, and backend permissions.


The Common Misconception

A frequent assumption is:

“If users can’t see or guess the ID, they won’t be able to access other resources.”

This often leads to frontend-only solutions like:

  • Encoding IDs in Base64

  • Hashing IDs in JavaScript

  • Mapping numeric IDs to random strings in the UI

While this may look cleaner, it does not provide real security.


Why Frontend Obfuscation Is Not Security

1. The Frontend Is Not a Trusted Layer

Anything running in the browser can be:

  • inspected

  • modified

  • replayed

Even if you hide the ID in the URL, the real identifier:

  • still reaches the backend

  • still appears in network requests

  • can be extracted from API responses

If your backend accepts it, an attacker can reuse it.


2. Predictable Access Patterns Still Exist

Changing this:

/offers/32

to something like:

/offers/7f3a9c

does not stop someone from:

  • intercepting a valid request

  • replaying it with another value

  • brute-forcing or enumerating resources

If the backend does not enforce ownership and permissions, the resource is still vulnerable.


A Realistic Attack Scenario

Imagine this API endpoint:

GET /offers/{offer_id}

If your backend logic is:

“If the offer exists, return it.”

Then anyone who gets a valid ID (hidden or not) can access data they should not see.

Security never lives in the URL.


What I Changed in My Project

In my case:

  • I initially used numeric IDs (/offers/32)

  • I later switched to UUIDs

  • I already had backend permission checks

This improved things — but only because of what happened on the backend, not because the ID looked nicer.


Why UUIDs Are Better (But Still Not Enough Alone)

Switching to UUIDs helps because:

  • they are hard to guess

  • they reduce enumeration risks

  • they look opaque to users

Example:

/offers/550e8400-e29b-41d4-a716-446655440000

However:

⚠️ UUIDs are not a security mechanism by themselves.

If your API returns a resource without checking permissions, a UUID won’t save you.


The Correct Approach: Backend-Centered Security

1. Always Enforce Permissions in the Backend

With FastAPI, every protected endpoint should verify:

  • who the user is

  • what they are allowed to access

Example (simplified):

@app.get("/offers/{offer_id}")

def get_offer(offer_id: UUID, user=Depends(get_current_user)):

offer = get_offer_from_db(offer_id)

if offer.owner_id != user.id:

raise HTTPException(status_code=403, detail="Forbidden")

return offer

This check is non-negotiable.


2. Treat IDs as Public Identifiers

Assume that:

  • IDs will leak

  • URLs will be shared

  • requests will be replayed

Design your API so that even with a valid ID, unauthorized access is impossible.


3. Use UUIDs for Exposure, Internal IDs for Internals

A solid pattern is:

  • internal numeric IDs (database performance)

  • external UUIDs (API exposure)

This gives you:

  • clean URLs

  • safer public identifiers

  • flexibility in your data model


Frontend Best Practices (Vue.js)

On the frontend side:

  • keep URLs simple and readable

  • don’t rely on obfuscation for protection

  • assume the backend is the source of truth

Vue.js should consume the API, not protect it.


Key Takeaways

  • Hiding IDs in frontend URLs is not security

  • The frontend is never a trusted layer

  • UUIDs help, but don’t replace permissions

  • Real security lives in the backend

  • FastAPI makes permission enforcement explicit and clean


Conclusion

If you’re spending time trying to “secure” your application by hiding IDs in Vue.js, you’re solving the wrong problem.

Focus on:

  • authorization

  • ownership checks

  • backend validation

Your future self (and your users) will thank you.


If you found this useful, feel free to share it or connect with me on LinkedIn.