In fact, one of my colleagues came up with a question - "Why the hell OAuth 1.0 uses two keys to sign messages..? Why Not just the consumer secret ?"
Well.. In fact - the exact reverse of this argument is one key point Eran Hammer highlights in his famous blog post - to emphasize why OAuth 1.0a is better...
"Unbounded tokens - In 1.0, the client has to present two sets of credentials on each protected resource request, the token credentials and the client credentials. In 2.0, the client credentials are no longer used. This means that tokens are no longer bound to any particular client type or instance. This has introduced limits on the usefulness of access tokens as a form of authentication and increased the likelihood of security issues."
Before I answer the question - let me very briefly explain OAuth 1.0a flow..
1. To become an OAuth consumer you need to have a Consumer Key and a Consumer Secret. You can obtain these from the OAuth Service Provider. These two parameters can be stored in a database or in the filesystem.
Consumer Key: A value used by the Consumer to identify itself to the Service Provider.
Consumer Secret: A secret used by the Consumer to establish ownership of the Consumer Key.
2. Using the Consumer Key and Consumer Secret, you need to talk to the OAuth Service Provider and get a Unauthorized Request Token.
Request to get the Unauthorized Request Token will include following parameters.
- oauth_consumer_key
- oauth_signature_method
- oauth_signature
- oauth_timestamp
- oauth_nonce
- oauth_version
- oauth_callback
As the response to the above token, you will get the following.
- oauth_token
- oauth_token_secret
- oauth_callback_confirmed
3. Now the OAuth Consumer, has the Request Token - and it needs to exchange this token to an Authorized Request Token. The Request Token needs to be authorized by the end user. So, the Consumer will redirect the end user to the Service Provider with following request parameter.
- oauth_token
As the response to the above, OAuth Consumer will get the following response.
- oauth_token
- oauth_verifier
The oauth_verifier is a verification code tied to the Authorized Request Token. The oauth_verifier and Authorized Request Token both must be provided in exchange for an Access Token. They also both expire together. If the oauth_callback is set to oob in Step 2, the oauth_verifier is not included as a response parameter and is instead presented once the User grants authorization to Consumer Application. The Service Provider will instruct the User to enter the oauth_verifier code in Consumer Application. The Consumer must ask for this oauth_verifier code to ensure OAuth authorization can proceed. The oauth_verifier is intentionally short so that a User can type it manually.
Both the above two parameters are returned back to the OAuth Consumer via a browser redirect over SSL.
4. Now the OAuth Consumer has the Authorized Request Token. Now it will exchange that to an Access Token. Once again the Access Token is per User per Consumer per Service Provider. Here the communication is not a browser re-direct but a direct communication between the Service Provider and the OAuth Consumer. This step is needed because, in step 3, OAuth Consumer gets the token through the browser.
The request to the access token will include following parameters.
- oauth_consumer_key
- oauth_token
- oauth_signature_method
- oauth_signature
- oauth_timestamp
- oauth_nonce
- oauth_version
- oauth_verifier
The signature here is generated using a combined key - Consumer Secret and Token Secret [from step -2 ] separated by an "&" character. I will explain later why two keys used here for signing.
As the response to the above, the Consumer will get the following...
- oauth_token
- oauth_token_secret
5. Now the OAuth Consumer can access the protected resource. The request will look like following.
- oauth_consumer_key
- oauth_token
- oauth_signature_method
- oauth_signature
- oauth_timestamp
- oauth_nonce
- oauth_version
The step - 5 does not required to be on TLS/SSL.
Let's get back to the original question...
Why the hell OAuth 1.0 uses two keys to sign messages..? Why Not just the consumer secret ?
During the OAuth flow there are three places where OAuth Consumer has to sign.
1. Request to get an Unauthorized Request Token. Here the request will be signed by the Consumer Secret only. ( Request for Temporary Credentials )
2. Request to get an Access Token. Here the request will be signed by the Consumer Secret and the Token Secret returned back with the Unauthorized Request Token in step - 2. ( Request for Token Credentials )
Why do we need two keys here ? It's for tighten security. What exactly that means..?
Have a look at step - 3. There the Consumer only sends the oauth_token from step - 2 to get User authorization. And as the response to this the Consumer will get the Authorized Request Token (oauth_token). Now in step - 4 Consumer uses this Authorized Request Token to get the Access Token. Here, the consumer needs to prove that - its the same consumer who got the unauthorized request token, now requesting for the Access Token. To prove the ownership of the Request Token, now the Consumer will sign the Access Token request with both the Consumer Secret and the Token Secret returned back with the Unauthorized Request Token.
3. Request to the protected resource. Here the request to the protected resource will be signed by the Consumer Secret and the Token Secret returned back with the Access Token in step - 4. ( Request for Resources )
Once again we need two keys here for tighten security. If OAuth only relies on the consumer secret for the signature, the person who steals can capture the access token [as it goes to the protected resource on HTTP] and signs the request with the stolen secret key. Then all the users of that OAuth Consumer will be compromised. Since we use two keys here, even though someone steals the consumer secret it cannot harm any of the end users - because it cannot get the Token Secret which is sent to the Consumer over SSL in step - 4. Also - you should never store Token Secrets at the Consumer end - that will reduce any risks of stealing Token Secrets. But, you need to store your Consumer secret as explained previously.
In any case if you have to store the Token Secret, then you need store it encrypted - and also make sure you store it in a different database from where you store your consumer secret. That is the best practice we follow when we store hashed passwords and the corresponding salt values.
Apart from the above benefit - the Token Secret can also act as a salt value. Since the request to the protected resource goes over the wire, a hacker can carry out a known plain text attack to guess the Key used to sign the message. If we only use the Consumer Secret, then all the users of the OAuth Consumer will be compromised. But, if we use the Consumer Secret with the Token Secret, then only that particular user will be compromised - not even the Consumer Secret.
Finally, OAuth presents a Bounded Token protocol over HTTP for accessing the protected resource. That means - each request to the protected resource the Conumer should prove that he owns the token, as well as - he is the one who he claims to be. In the bounded token model, an issued token can only be used by the exact person who the token was issued to. [Compare this with Bearer token in OAuth 2.0]. To prove the identity of the Consumer it self, it can sign the message it self with consumer_secret. To prove that he also owns the token, he needs to sign the message token_secret too. Anyone can know the Access Token, but it's only the original Consumer knows the token_secret. So the key to sign is derived from combining both the keys.