"The Worst Uses of UUIDs I've Seen" Part 2: API Antipatterns

    May 13, 2024
    9 min read
    Opinion
    Fun
    uuid
    opinion
    testing
    best-practices

    UUIDs are amazing — until someone puts them in a public API like they're a security token or a substitute for good design.

    This is Part 2 of our ongoing "What not to do with UUIDs" series. We’re leaving the database trenches behind and heading into the wild world of API design, where UUIDs are often misunderstood, misused, and mistaken for magic.

    Here are the most facepalm-worthy antipatterns I've encountered — and what you should do instead.


    😬 Antipattern 1: “UUIDs Are Secure Because They're Long”

    The scenario:

    A password reset flow uses a UUIDv4 in a link:

    code
    /reset-password/2cf92d3e-3814-4422-bd11-93e15a601cdc

    The belief: “This UUID is random, so users can’t guess it.”

    Reality:

    • UUIDv4 is not encrypted
    • UUIDv1 can be guessable if timestamps and MAC addresses are exposed
    • URLs can be leaked via logs, analytics, browser history

    ✅ Fix:

    • Use a secure random token (crypto.randomBytes, secrets.token_urlsafe)
    • Store a hashed token in the database
    • Include expiry and user binding

    > UUIDs are not secrets — they're just IDs.


    🌀 Antipattern 2: Accepting UUIDs in Every Format

    The scenario:

    Your API accepts UUIDs in these forms:

    • 550e8400-e29b-41d4-a716-446655440000
    • 550e8400e29b41d4a716446655440000
    • 550E8400-E29B-41D4-A716-446655440000
    • Base64-encoded, because... why not?

    Clients start sending all of them. Your backend starts converting, guessing, and eventually breaks when parsing fails.

    ✅ Fix:

    • Standardize the UUID format in your API spec
    • Accept lowercase, hyphenated format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
    • Validate UUIDs on input using strict regex or UUID parser libs

    > Ambiguity is the enemy of robust APIs.


    🙈 Antipattern 3: UUIDs With No Meaning or Labels

    The scenario:

    A response looks like:

    json
    {
      "id": "550e8400-e29b-41d4-a716-446655440000"
    }

    Great... but what is this ID? A user? A project? An invoice?

    Now imagine this in a list of 10 different resources — all with id.

    ✅ Fix:

    • Use resource-type prefixes or contextual field names:
    json
    {
      "user_id": "uuid...",
      "project_id": "uuid..."
    }
    • Even better: include object types in nested responses
    json
    {
      "user": {
        "id": "uuid...",
        "name": "Jane"
      }
    }

    > UUIDs are only useful if clients understand what they refer to.


    🔁 Antipattern 4: Using UUIDs Without Pagination or Filtering

    The scenario:

    You fetch 5,000 results with UUIDs and zero filtering:

    code
    GET /orders

    The server returns:

    json
    [
      { "id": "uuid1", ... },
      { "id": "uuid2", ... },
      ...
    ]

    Pagination? Sorting? Nope.

    ✅ Fix:

    • Paginate with UUIDs using ?after=uuid
    • Sort with created_at or uuidv7-style sortable IDs
    • Offer filtering by UUIDs (?id=uuid1,uuid2)

    > UUIDs aren’t naturally ordered — you need to guide clients.


    🔒 Antipattern 5: Relying on UUIDs for Authorization

    The scenario:

    http
    GET /users/550e8400-e29b-41d4-a716-446655440000

    The backend fetches and returns the user — no auth checks, assuming the UUID is "unguessable."

    Spoiler: it's not.

    ✅ Fix:

    • Always check that the authenticated user has access to the UUID
    • Never assume “random = secure”
    • Use contextual authorization — not obscurity

    > Security through obscurity is not security. It’s tech theater.


    😱 Antipattern 6: Logging UUIDs Without Caution

    The scenario:

    You log every UUID in every API request:

    code
    GET /users/uuid - [user_uuid=uuid] - auth_token=...

    Guess what: now UUIDs are in your logs, your analytics tools, your monitoring dashboards. If you use them as identifiers or keys, they’re now... public.

    ✅ Fix:

    • Mask or redact UUIDs in logs if they're sensitive
    • Don’t log them next to auth tokens or emails
    • Rotate UUIDs if exposed (in the rare case you used them as secrets)

    🔁 Bonus Antipattern: UUIDs in PATCH with No Schema Validation

    Clients sometimes send PATCH requests like:

    json
    {
      "id": "uuid-not-even-valid-1234"
    }

    The server accepts it blindly, stores garbage, and breaks on the next query.

    ✅ Fix:

    • Validate all incoming UUIDs
    • Reject malformed UUIDs with 400
    • Use a real schema validator (zod, pydantic, Joi, etc.)

    Final Thoughts

    UUIDs are powerful. But they’re not magical.

    They don’t make APIs secure by default. They don’t replace authorization checks. And they definitely shouldn’t be used as blind tokens in public URLs.

    Use them for what they’re great at: uniqueness, global traceability, and distributed consistency.

    But when designing your APIs, remember:

    > A UUID is just a string — and a poor substitute for security, structure, or sensible design.

    🙈 Part 3 is coming soon: "Front-End Fails and UX Nightmares"

    Generate Your Own UUIDs

    Ready to put this knowledge into practice? Try our UUID generators:

    Generate a Single UUID

    Create a UUID with our fast, secure generator

    Bulk UUID Generator

    Need multiple UUIDs? Generate them in bulk

    Summary

    This article explores real-world examples of UUID misuse in API design — from leaky abstractions to security flaws — and shares practical advice to help you avoid the most common and cringe-worthy antipatterns.

    TLDR;

    UUIDs can make your API better — or worse — depending on how you use them.

    Key API antipatterns and takeaways:

    • Using UUIDs as public secrets is not secure
    • Allowing multiple UUID formats creates bugs and ambiguity
    • Returning UUIDs with no context leads to confusion for clients

    UUIDs are great for uniqueness — but not for obfuscation, authorization, or human-facing tokens.

    Cookie Consent

    We use cookies to enhance your experience on our website. By accepting, you agree to the use of cookies in accordance with our Privacy Policy.