Its never good when specifications are read like the bible, where people find in it what they want.
Over the past few months I have been getting many questions about requirements in the OAuth Core 1.0 specification, as well as finding significant issues with existing implementations. I agree that the specification isn't clear on many of these issues, but until we have a replacement, I hope this list would help.
Consumers are required to generate a unique nonce value for each request with the same timestamp:
"The Consumer SHALL then generate a Nonce value that is unique for all requests with that timestamp." (Section 8).
However, there is currently no requirement for the Service Provider to check or enforce the nonce:
"When verifying a Consumer signature, the Service Provider SHOULD check the request nonce to ensure it has not been used in a previous Consumer request." (Section 9)
For those not intimately familiar with RFC 2119, SHOULD means:
"that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course."
There are plenty of places where APIs don't need to worry about replay attacks, the only attacks solved by checking the nonce. For example, requests over HTTPS or non-confidential read-only requests don't benefit much from using nonces. APIs for ordering pizza, on the other hand, do.
Developers must consider the threat model and security requirements of their applications, and if checking the nonce adds value, they should do it. However, this requirement is likely to change in future versions (making nonce checks mandatory).
Parameter Transmission Methods
OAuth defines three methods for including OAuth parameters in the HTTP request: URI query, form-encoded body, and HTTP Authorization header. Many providers assume that they can pick and choose which methods to support. This is wrong.
Now, granted, the specification does an awful job making this clear. First, it has some contradictions, and second, it does not use normative directives (MUST, SHALL, SHOULD, etc.) to define the required behavior.
The Consumer requirements, even though they lack normative directives, specifically calls for using one of the three methods:
"OAuth Protocol Parameters are sent from the Consumer to the Service Provider in one of three methods" (Section 5.2)
This implies two things: the Consumer must only use one method at a time, and can pick any of the three and expect it to work. If the server offers additional methods, they Consumer may use those as well:
"In addition to these defined methods, future extensions may describe alternate methods for sending the OAuth Protocol Parameters."
But then the specification contradicts itself:
"It is RECOMMENDED that Service Providers accept the HTTP Authorization header."
So what we have here is an implicit requirement for Consumers to use one of three defined methods, and allowing Consumer the freedom to use either one (with an order of preference defined), but allowing the Service Providers to omit HTTP Authorization header support. This is broken.
This problem has been made worse by the OAuth Discovery specification which made the methods a matter of configuration. Note that listing which methods are supported is not listed in the configuration documentation requirements of the core protocol.
For lack of better guidance, I would offer this:
Providers must support all three methods. Consumers should use the first method available to them from the list (in the order listed). If a Consumer request fails due to unsupported method, it should attempt making the request with another method. Providers should avoid coming up with new parameter transmission methods until this issue is resolved.
I expect future versions of the specification to require a basic set of methods from all servers, and would personally like to see the Authorization header as the primary method.
During the specification development process, we had several discussions about parameter names and restrictions. OAuth parameters start with the 'oauth_' prefix, while server specific parameters don't.
The two main areas of confusion are:
- What prefix should extensions use?
- What should providers do with unrecognized parameters?
The specification offers a few hints:
"OAuth Protocol Parameters" are defined as "Parameters with names beginning with oauth_." (Section 3)
"Service Provider specific parameters MUST NOT begin with oauth_." (Section 4.2)
"OAuth Protocol Parameter names and values are case sensitive. Each OAuth Protocol Parameters MUST NOT appear more than once per request, and are REQUIRED unless otherwise noted." (Section 5)
Putting this all together, the specification allows extensions to define new 'oauth_' parameters. It only restrict server-specific parameters from using the prefix. In other words, if the behavior isn't server-specific (i.e. plays well with others, interoperable), it is acceptable and allowed.
However, such extensions are still restricted in their use of 'oauth_' parameters:
- Parameters names and values are case sensitive
- They cannot repeat
- Are required unless explicitly noted otherwise.
So to answer the first question, extensions should use the 'oauth_' prefix (and not 'xoauth_' or other such proposals). Individual services should not use it to define their own, incompatible, proprietary extensions.
This provides us with the answer to the second question. Providers should ignore any 'oauth_' parameters they do not recognize. They should not fail the entire request just because it includes an unknown 'oauth_' parameter. They should however, include such parameters in the signature and verify they have not been tempered with.
Want more proof that this is the specification's intention? Section 10 defines a few error conditions:
- Unsupported parameter
- Unsupported signature method
- Missing required parameter
- Duplicated OAuth Protocol Parameter
Note that the first three errors are generic and talk about parameters in general, not just 'oauth_'. The last error is specific to 'oauth_' parameters. This is intentional. Note that there is no error for unknown OAuth Protocol Parameter.
OAuth intentionally includes a protocol version. This version is meant for two primary objectives:
- Define the meaning of 'oauth_' parameters listed in the specification
- Define the signature workflow
Any parameter undefined by OAuth is not allowed to change how the protocol works. It may add additional functionality but it will not affect how the core protocol is implemented. This is important because it means providers can safely ignore unknown parameters without introducing security issues within the core protocol.
The reason why I want servers to simply ignore unknown 'oauth_' parameter is because I expect new extensions to introduce just such parameters. If providers hard-code which parameters are valid today, they will create problems when new Consumer libraries add such support.