Skip to content

Why not OAuth

Every developer asks this, and it deserves a real answer rather than a dismissal.

Short version: OAuth handles the delegation half well. The half that matters here — confidentiality through an intermediary — is outside what OAuth does, by design.

Credit where it’s due. OAuth is the right answer to a large class of problems:

  • Delegation with scopes. “This application may act for this user, limited to these operations.” Well understood, well tooled, and auditors recognise it.
  • Conveying which user. A token can carry the subject, so a resource server sees the person rather than only the application.
  • Immediate central revocation. Revoke the token and access stops everywhere at once.
  • No key management burden. Developers do not handle key material.

If those are your requirements, use OAuth. This design exists because of three requirements it cannot meet.

OAuth authorises; it never encrypts payloads. TLS protects a hop, and a relay terminates that hop — so anything passing through an intermediary is plaintext to it.

That makes the central property here inexpressible: an agent that routes a reply but cannot read it. There is no configuration of bearer tokens that hides content from the party carrying it.

This is not a gap in OAuth. Payload confidentiality was never its job.

OAuth consent is a screen at the identity provider, shown once, producing a token. Every use afterwards is unattended — that is precisely the point of a token.

Here, consent must happen per request, and it must be something no other component can perform. Approving a request is a cryptographic operation using a key only the user holds. Declining is simply an operation that does not happen.

To approximate this in OAuth you would add a flag that some service checks — which is the thing being replaced. A permission check can be bypassed by a bug. An operation nobody else can perform cannot.

OAuth cannot function without a live IDP. Issuance, refresh and usually validation all require reaching it. Three consequences:

  • A hard dependency. IDP unavailable means nobody authenticates.
  • It sits in the path. The provider observes who talks to whom and how often. Here, keys are issued and the platform then steps out — it never sees the traffic.
  • A shared trust root is required. Two organisations need a common or federated provider. Two agents that have never met need no such thing.

There is a fourth, subtler one: OAuth needs pre-registered clients. Client IDs, secrets, redirect URIs, registered in advance at the resource owner’s provider. Addressing a party you have not met requires none of that here — you can encrypt to an identity that has not been registered at all. This is what dynamic client registration and federation specs exist to work around.

OAuthThis design
Enrollment and onboardingstrongmanual
Scope-based delegationstrongpolicy rules
Immediate global revocationstrongkey expiry plus policy
Tooling and familiaritystrongnewer
Confidentiality through a relaynot applicablenative
Per-request consentno primitivenative
Operating with no authority in the pathnoyes
Addressing an unregistered partyrequires registrationnative

To obtain these properties with OAuth you would add encrypted payloads, a per-request signing key held by the user, and something preventing the intermediary from decrypting. At that point you have rebuilt this design with OAuth as the enrollment step.

Which is a perfectly reasonable architecture. OAuth is good at onboarding, provisioning and revocation. It is not built to be the data path when an intermediary must be excluded from the content.

Use both, for what each is good at.

The relay property is not aesthetic. It is what makes breach safe harbour available under GDPR Art. 34(3)(a) and HIPAA: an intermediary holding only ciphertext it cannot decrypt changes what a breach of that intermediary means.

With bearer tokens the relay holds readable data, and that exemption is unavailable.