Designing “Just Enough” API Security for Solo Developers
Source: Dev.to
Don’t aim for perfection.
Protect your API in layers.
Why API security is hard for solo developers
- Unlimited attack surface: once you start thinking about security, the list of possible attacks never ends.
- Anxiety loop: “What if this attack happens?” → “What about that scenario?” → difficulty moving forward.
- Limited resources: you can only manage a finite number of defenses, so you need clear boundaries.
Defining the scope
Before implementing anything I asked myself:
- What I would consider – threats I must protect against.
- What I would intentionally ignore – attacks that are out of scope for a solo project.
This wasn’t a formal threat model; it evolved while building the API.
What to protect
- Unauthenticated requests
- Invalid or malformed parameters
- Requests with stolen or replayed JWTs
What to ignore
- Perfect secrecy of client‑side code
- Defenses against full reverse‑engineering of native apps
- Stopping every possible attack at the API layer alone
Layered security approach
I split responsibilities across three layers. No single layer is trusted completely.
Layer 1 – Client
- JWT for user authentication
- Signature (HMAC) for application identification
Layer 2 – API (Cloudflare Workers + Hono)
- Application validation (request signing)
- JWT verification and user identification
- Basic request validation (method, path, parameters)
- Lightweight rate limiting
Layer 3 – Database (Supabase)
- Row‑level security (RLS) to enforce per‑user data isolation
Rule: even if the API is bypassed, other users’ data must never be accessible. Supabase RLS enforces this at the database level.
Application‑level verification
To verify the calling application I use request signing (HMAC) but intentionally avoid:
- Signing the request body
- Strict nonce management
- Perfect replay protection
Instead, I sign only:
timestamp- HTTP
method - Request
path
This trade‑off balances implementation cost, operational complexity, and the actual threat level. Since the secret key lives in the client (React Native), full HMAC‑level rigor isn’t realistic for solo development.
Related article: Protecting the API Entry Point with Cloudflare Workers
Logging and observability
- Every request receives a unique
requestId. - Logs are structured JSON, ready for aggregation.
- Error responses to clients are minimal; internal logs clearly distinguish authentication vs. authorization failures.
- In the demo the logs go to the console, but swapping the output to a production‑grade logger is straightforward.
Step‑by‑step design process
The order that worked best for me:
- Fix assumptions – define the client and the users.
- Decide threat boundaries – what must be protected vs. what can be ignored.
- Lock down the database – enable RLS to prevent cross‑user access.
- Confirm user identity – implement JWT authentication.
- Validate requests at the API entry – basic validation, reject unexpected traffic.
- Add application‑level identification if needed – signatures / timestamps.
- Throttle unintended request bursts – rate limiting.
- Make issues traceable –
requestIdand structured logs.
Following this sequence gave me an API design that is not overengineered but difficult to break accidentally.
Demo repository
The full demo can be found at:
Related article: How I Designed Supabase and Row Level Security (RLS)
Conclusion
Designing security “correctly” from day one is extremely difficult, especially when you’re working alone. By:
- setting clear boundaries,
- layering defenses, and
- making observability a first‑class concern,
you can achieve “just enough” security without drowning in complexity. I hope this article helps you decide how far your own API security should go.