OAuth Echo is a means to securely delegate OAuth authorization with a third party while interacting with an API. Within the Twitter ecosystem, we use OAuth Echo as a means to allow your application to use services such as Twitpic and yfrog.
OAuth Echo is still OAuth. OAuth Echo does not require xAuth (don't let those x_* headers fool you, that's just the standard way to define custom HTTP headers).
There are four parties involved in this interaction:
- the User who is using Twitter through a particular, authorized Twitter application
- the Consumer, or the Twitter application that is attempting to interact with the 3rd party media provider (e.g. the photo sharing site)
- the Delegator, or the 3rd party media provider; and
- the Service Provider a.k.a. Twitter itself.
Essentially, you will be preparing a request for the delegator to send to the Twitter API on your application and user's behalf. You'll be sticking what would otherwise be a signed OAuth request into an HTTP header and asking the delegator to send that request to Twitter after completing the intermediary operation.
So, let's go: the User wants to upload a photo. The Consumer is going to call upload on the Delegator with a POST. The POST should contain the image, but it should also contain two additional items as HTTP headers:
- X-Auth-Service-Provider — effectively, this is the realm that identity delegation should be sent to — in the case of Twitter, just set this to https://api.twitter.com/1/account/verify_credentials.json. iOS5-based Twitter integrations will add an additional application_id parameter to this URL that will also be used to calculate the oauth_signature used in X-Verify-Credentials-Authorization.
- X-Verify-Credentials-Authorization — Consumer should create all the OAuth parameters necessary so it could call https://api.twitter.com/1/account/verify_credentials.json using OAuth in the HTTP header (e.g. it should look like OAuth oauth_consumer_key="...", oauth_token="...", oauth_signature_method="...", oauth_signature="...", oauth_timestamp="...", oauth_nonce="...", oauth_version="..." ).
Keep in mind that the entire transaction period needs to occur within an amount of time where your oauth_timestamp will still be valid.
Alternatively, instead of sending these two parameters in the header, they could be sent in the POST as x_auth_service_provider and x_verify_credentials_authorization — if you do this, then remember to escape and include the parameters in your OAuth signature base string — similar to how you would encode parameters in any request. It's best to use HTTP headers to keep the operations as separate as possible.
The Delegator's goal, at this point, is to verify that the User is who he or she says he or she is before it saves the media. Once the Delegator receives all the data above via its upload method, it should temporarily store the image, and then construct a call to end point specified in the X-Auth-Service-Provider header — in this case, https://api.twitter.com/1/account/verify_credentials.json, using the same OAuth authentication header provided by the Consumer in the X-Verify-Credentials-Authorization header.
Please note that one should use the URL provided to them by X-Auth-Service-Provider to perform the look up, not a hard coded value on your servers. Apple iOS5, for example, adds an additional application_id parameter to all OAuth requests, and its existence should be maintained at each stage of OAuth Echo.
For the OAuth authorization portion, it should take the header value in X-Verify-Credentials-Authorization, and stick that into it's own Authorization header for its call to the service provider. For good measure, you should also confirm that the value in X-Auth-Service-Provider is what it should be.
- If the Service Provider returns a HTTP 200, then we're good. The Delegator should permanently store the image, generate a URL, and return it.
- If the Service Provider doesn't return a HTTP 200, then dump the image, and then return an error back to the Consumer.
You can read @raffi's original proposal for OAuth Echo.
Adapted from @raffi's original post.