---
id: 30
title: "Use the standard; don't reinvent the protocol"
status: current
date: 2026-06-12
authors:
  - "Theo Zourzouvillys"
tags: [architecture, security, api, interop]
references:
  - id: problem-details
    title: "RFC 9457 — Problem Details for HTTP APIs"
    url: https://www.rfc-editor.org/rfc/rfc9457
    abstract: "A standard JSON format for returning machine-readable error details from an HTTP API — type, title, status, detail, instance — so clients can handle errors consistently instead of every API inventing its own error shape. (Obsoletes RFC 7807.)"
  - id: openid-connect
    title: "OpenID Connect"
    url: https://openid.net/developers/how-connect-works/
    abstract: "An identity layer on top of OAuth 2.0 that standardises authentication — how a client verifies a user's identity via an identity provider and obtains profile information — built and hardened by a large community of identity and security experts over more than a decade."
  - id: jose
    title: "JOSE / JWT (JSON Object Signing and Encryption)"
    url: https://datatracker.ietf.org/wg/jose/about/
    abstract: "The IETF family of standards (JWT, JWS, JWE, JWK, JWA) for representing signed and encrypted claims as JSON — the widely-implemented, reviewed basis for tokens, rather than a bespoke signing scheme."
summary: "When a standard exists for a common or complex problem, use it — don't reinvent the protocol. Standards encode huge adversarial expertise, especially in auth and crypto; a partial implementation beats rolling your own. You're not that special, and your problem isn't either."
supersedes: null
superseded_by: null
aliases: []
---

## TL;DR

If a **standard already exists for a common or complex problem, use it.** Don't reinvent the protocol,
the token format, the error shape, the signing scheme. A standard is the crystallised output of a lot
of people — often over many years, adversarially — solving exactly your problem and finding the edge
cases, attacks, and interop traps you haven't thought of yet. [OpenID Connect](ref:openid-connect),
[JWTs](ref:jose), [HTTP Message Signatures](/zfn/7-sign-the-message/), [DPoP](/zfn/6-sender-constrained-tokens-dpop/),
[Problem Details](ref:problem-details) — all are examples of "someone already did this, well." Even a
**partial** implementation (not everything on day one, maybe not ever) beats a bespoke one: you get
interop, tooling, a known mental model, and a path to completeness.

Some standards genuinely are overkill — that's a real exception. But the default, especially anywhere
near **authentication or cryptography**, is: **you're not that special, and your problem isn't either.**
The experts who built these spent far more effort getting them secure than you can afford to.

## Context

The instinct to build it yourself is strong, and usually wrong. It comes from a few places: the
standard *looks* heavier than your immediate need; you don't want a dependency; or — most often,
honestly — you think your situation is special. It very rarely is. Common problems have common
solutions for a reason, and complex problems have *standardised* solutions because many people
independently hit the same walls and eventually agreed on how to get past them.

What you're really buying when you adopt a standard is **everyone else's mistakes, already made and
fixed**. The error format that handles the cases you'd discover in production six months from now. The
token format whose every field exists because someone got burned without it. The auth protocol that has
survived a decade of people actively trying to break it. Rolling your own means re-running that entire
gauntlet alone, on your time, with your users as the test subjects — and you will get a subset of it
wrong, because the people who wrote the standard were smart and motivated and *still* needed many
revisions to get it right.

This is most acute in **security and cryptography**, where "looks fine" and "is fine" are completely
different things and the gap is invisible until it's exploited. "Don't roll your own crypto" is a cliché
because it is true: the failure modes are subtle, non-obvious, and catastrophic, and the only defense is
the enormous, sustained, adversarial expert review that standards like OpenID Connect, JOSE, DPoP, and
HTTP Message Signatures have had and your weekend implementation has not.

## Recommendation

**Reach for the standard first; build your own only with a real reason.**

- **For a common or complex problem, find the standard and use it.** API error bodies →
  [Problem Details](ref:problem-details). Tokens → [JWT/JOSE](ref:jose). Delegated auth and identity →
  OAuth 2.0 / [OpenID Connect](ref:openid-connect). Sender-constrained tokens →
  [DPoP](/zfn/6-sender-constrained-tokens-dpop/). Message integrity/provenance →
  [HTTP Message Signatures](/zfn/7-sign-the-message/). API contracts → an established schema language
  ([ZFN-14](/zfn/14-schema-first-apis-generate-clients/)). The list goes on (OpenTelemetry, semver,
  iCalendar, HTTP caching, TLS…). The point is to *look first*.
- **Never roll your own crypto or auth.** This is the hard version of the rule. The expertise gap is
  unbridgeable on a normal timeline, and the cost of a subtle mistake is a breach. Use the vetted
  protocol and a vetted library; don't invent a signing scheme, a session format, or a password flow.
- **Partial is fine — but do the security-critical parts correctly.** You don't have to implement an
  entire standard on day one (or ever) to benefit; a conformant subset still gives you interop and a
  clear path. The one caveat: for a *security* standard, the parts that provide the security are not
  optional. A "DPoP" that skips verifying the proof, or a "JWT" that doesn't check the signature, is not
  a partial implementation — it's an insecure one. Implement the safety-bearing parts properly or you've
  built the bespoke thing you were avoiding.
- **The honest exception: some standards are overkill.** A few are over-engineered, or far heavier than
  a genuinely simple, local, low-stakes problem warrants. When the problem is small, common-but-trivial,
  and not security-sensitive, a tiny bespoke solution can be the right call. The filter is "common *or*
  complex *or* security-adjacent" — if any of those is true, default to the standard; reinvent only when
  none is and the standard truly doesn't fit.
- **Check your motive.** If the reason for building your own is "ours is special" or "I don't want the
  dependency," be suspicious — that's usually NIH and ego, not engineering. You're almost certainly not
  the special case.

## Consequences

**Easier:**

- You inherit years of adversarial expert review for free — especially the security properties you could
  not realistically get right alone.
- Interop, libraries, tooling, and documentation already exist; new engineers already know the standard;
  other systems already speak it.
- Less code you own and have to secure, debug, and maintain forever.
- A clear path to "more complete later" instead of a bespoke dead end.

**Harder:**

- A standard can be heavier than your immediate need, with a learning curve and concepts you don't use
  yet — real up-front cost against a large downstream saving.
- Partial adoption of a *security* standard is a trap if you skip the parts that make it secure; you have
  to understand which parts those are.
- Occasionally a standard genuinely doesn't fit, or is over-engineered for a trivial case, and telling
  that apart from NIH takes honest judgement.
- Some "standards" are really one vendor's format; prefer the open, widely-implemented, independently-
  reviewed ones.

## References

- [OpenID Connect](ref:openid-connect), [JWT/JOSE](ref:jose), [Problem Details](ref:problem-details) —
  worked examples of "the problem is already solved, well."
- [ZFN-6](/zfn/6-sender-constrained-tokens-dpop/) (DPoP) and [ZFN-7](/zfn/7-sign-the-message/) (HTTP
  Message Signatures) — security standards to adopt rather than reinvent; ZFN-7 also says don't roll your
  own canonicalization.
- [ZFN-5](/zfn/5-platform-workload-identity-service/) — built on standard token formats and verification,
  not a homegrown identity scheme.
- [ZFN-14](/zfn/14-schema-first-apis-generate-clients/) — use a standard schema language for API
  contracts rather than a bespoke one.

## Changelog

- **2026-06-12**: First published as a Field Note.
