twobotechnologies

Authorization · 4 min read

OAuth 1.0a vs OAuth 2.0: What Still Matters Today

Short answer

OAuth 1.0a (RFC 5849) signs each API request with HMAC-SHA1 or RSA using a consumer secret and a token secret, while OAuth 2.0 (RFC 6749) sends bearer tokens over TLS and moves security into flows, PKCE and token lifetimes; new APIs use OAuth 2.0, but some long-lived APIs still accept 1.0a.

Key takeaways

  • OAuth 1.0a request signing protects each call even without TLS; OAuth 2.0 bearer tokens depend on TLS.
  • Most signature bugs in OAuth 1.0a come from building the signature base string: encoding, parameter sorting and the URL.
  • If you need per-request proof in OAuth 2.0, look at DPoP (RFC 9449) or mutual TLS (RFC 8705).

OAuth 1.0a and OAuth 2.0 share a name and a goal, letting a user grant an application limited access to an API, but they are different protocols with different security models. If you maintain an integration with an API that still speaks 1.0a, or you are wondering why 2.0 dropped request signatures, here is how they compare.

What did OAuth 1.0a do?

OAuth 1.0a signs every API request with a key derived from the client's consumer secret and the user's token secret, so the server can verify each call came from the holder of both.

The protocol, published as RFC 5849 in 2010, has three legs: the client gets a temporary request token, sends the user to approve it, then exchanges it for an access token and token secret. After that, every API call carries an Authorization: OAuth ... header with oauth_consumer_key, oauth_token, oauth_nonce, oauth_timestamp, oauth_signature_method and oauth_signature.

The "a" fixed a session fixation flaw found in 2009 in the original 1.0 draft, by adding the oauth_verifier and oauth_callback_confirmed parameters.

How is the OAuth 1.0a signature built?

You build a signature base string from the HTTP method, the normalized URL and the sorted, percent-encoded parameters, then sign it with HMAC-SHA1 using the key consumer_secret&token_secret.

  1. Collect all parameters: query string, form body (if application/x-www-form-urlencoded) and the oauth_* values, excluding oauth_signature.
  2. Percent-encode each name and value with RFC 3986 rules (spaces become %20, not +).
  3. Sort by name, then by value.
  4. Join as name=value pairs with &, then percent-encode the whole thing again.
  5. Concatenate: METHOD&encoded_base_url&encoded_parameter_string.
  6. Sign with HMAC-SHA1, base64-encode, and percent-encode into the header.

Nearly every "invalid signature" error comes from steps 2 to 4: double encoding, + instead of %20, a port number left in the URL, or a JSON body wrongly included in the parameters. Use a well-tested library and compare its base string with the API's examples when debugging.

What did OAuth 2.0 change?

OAuth 2.0 dropped per-request signatures in favor of bearer tokens over TLS, and added several flows for different kinds of clients.

OAuth 1.0a OAuth 2.0
Spec RFC 5849 (2010) RFC 6749, RFC 6750 (2012)
Request protection Signature on every call TLS; bearer token
Client types Mainly server apps Web, SPA, mobile, devices, machine-to-machine
Token lifetime Often indefinite Short access tokens, refresh tokens
Complexity for callers High (signing) Low (add a header)
Current guidance Maintenance only RFC 9700 best practice, OAuth 2.1 draft

The trade-off was deliberate. Signing proved too hard for many developers, and TLS had become universal. The cost is that a bearer token is valuable to whoever steals it, which is why OAuth 2.0 practice leans so hard on short lifetimes, narrow scopes, PKCE and, where needed, sender-constrained tokens.

When would I still call a 1.0a API?

When an established API still requires it for some operations, or when you integrate with an older internal service that was built around it.

Some long-running public APIs kept OAuth 1.0a for user-context calls while adding OAuth 2.0. The X (Twitter) API is the best-known example: its documentation describes both OAuth 1.0a user context and OAuth 2.0 with PKCE. Always check the current provider documentation, because supported methods change.

How do I get 1.0a-style guarantees in OAuth 2.0?

Use sender-constrained tokens: DPoP (RFC 9449) or certificate-bound tokens with mutual TLS (RFC 8705).

With DPoP, the client generates a key pair, includes a signed proof JWT with each request (method, URL, timestamp and a hash of the access token), and the server checks the proof against a key thumbprint bound into the token. A stolen token alone is no longer enough. It is the modern answer to what 1.0a signatures were trying to achieve. The article on modern OAuth techniques covers DPoP and pushed authorization requests in more detail.

To build an OAuth 2.0 authorization request correctly, use the Authorization URL Builder.

Questions

Is OAuth 1.0a insecure?

Not inherently. Its request signing is sound when implemented correctly. Its problems are complexity, poor fit for browser and mobile clients, and HMAC-SHA1, which is still considered safe for HMAC but looks dated. New designs choose OAuth 2.0.

Does the X (Twitter) API still use OAuth 1.0a?

X documents both OAuth 1.0a user context and OAuth 2.0, including the authorization code flow with PKCE, for its API. Check its developer documentation for which endpoints accept which method, since this has changed over time. This site is not affiliated with X Corp.

Can OAuth 2.0 sign requests like 1.0a did?

Not in the core spec. DPoP has the client sign a small proof JWT per request, and mutual TLS binds tokens to a client certificate. Both give a stolen token much less value.

Sources

Tagged: OAuth, OAuth 2.0, API, X (Twitter) API, REST

The Twobo Technologies editors write practical explainers on identity and API security and maintain the free tools on this site. Spotted an error or an outdated detail? Email contact@twobotechnologies.com.

Related articles