Note

Bash OAuth library has been move to GitHub, the links in this post are not updated, please head over to GitHub for the files.

I have used a Python OAuth library for a few of my scripts. Some of my scripts are Bash scripts, I didnt want to rewrite them using Python. A little wild idea came up in my mind, I decided to use Bash to write a library and make those Bash scripts work with that library.

So, OAuth.sh was born.

After I finished this library, it actually is not too complicated. However this library still needs two external programs, one is Perl for percent-encoding1, the other is OpenSSL for HMAC-SHA1. I think its possible that Bash can do these two jobs, but that might take a lot of extra efforts to make so.

Now, I will show you how to use this library. Basically, I will use Twitters Authenticating Requests (3-legged OAuth) as template, only focus on how to get the values not the OAuth specification. I use it here because Twitter is what I written this library for. I want to update my profile image from shell, I used to use one curl to update, but now its a little different.

I have also made a script, test_OAuth.sh , so you can run it to see the calculated values for real.

1   Acquiring a request token

First, we have the following variables:

oauth_consumer_key='GDdmIQH6jhtmLUypg82g'
oauth_consumer_secret='MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98'
oauth_signature_method='HMAC-SHA1'
oauth_version='1.0'
oauth_nonce='QP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk'
oauth_timestamp='1272323042'
oauth_callback='http://localhost:3005/the_dance/process_callback?service_provider_id=11'

We need to create an array to specify what are needed to be used for signing:

params=(
  $(OAuth_param 'oauth_consumer_key' "$oauth_consumer_key")
  $(OAuth_param 'oauth_signature_method' "$oauth_signature_method")
  $(OAuth_param 'oauth_version' "$oauth_version")
  $(OAuth_param 'oauth_nonce' "$oauth_nonce")
  $(OAuth_param 'oauth_timestamp' "$oauth_timestamp")
  $(OAuth_param 'oauth_callback' "$oauth_callback")
  )

OAuth.sh provides OAuth_param for generating a key=value, both key and value would be automatically percent-encoding encoded.

Then we get the base string:

base_string=$(OAuth_base_string 'POST' 'https://api.twitter.com/oauth/request_token' ${params[]})

We use OAuth_base_string to generate, then pass it to _OAuth_signature to get the signature.

signature=$(_OAuth_signature "$oauth_signature_method" "$base_string" "$oauth_consumer_secret" "$oauth_token_secret")

Note that the last parameter $oauth_token_secret is an empty value since we havent had a token yet.

Put the signature to the HTTP header

params[${#params[]}]=$(OAuth_param 'oauth_signature' "$signature")

Generate header string

header="$(_OAuth_authorization_header_params_string ${params[]})"

About the parsing the response is just shell scripting skill, you can see the TwitterOAuth.sh for that and how it uses curl to request.

The next two steps, Sending the user to authorization and Exchanging a request token for an access token, are not too difficult. Please read the source code.

2   Making a resource request on a users behalf

The first few steps are similar.

status='setting up my twitter 私のさえずりを設定する'
oauth_token='819797-Jxq8aYUDRmykzVKrgoLhXSq67TEa5ruc4GJC2rWimw'
oauth_token_secret='J6zix3FfA9LofH0awS24M3HcBYXO5nI1iYe8EfBA'
oauth_nonce='oElnnMTQIZvqvlfXM56aBLAf5noGD0AQR3Fmi7Q6Y'
oauth_timestamp='1272325550'

params=(
  $(OAuth_param 'oauth_consumer_key' "$oauth_consumer_key")
  $(OAuth_param 'oauth_signature_method' "$oauth_signature_method")
  $(OAuth_param 'oauth_version' "$oauth_version")
  $(OAuth_param 'oauth_nonce' "$oauth_nonce")
  $(OAuth_param 'oauth_timestamp' "$oauth_timestamp")
  $(OAuth_param 'oauth_token' "$oauth_token")
  $(OAuth_param 'status' "$status")
  )

base_string=$(OAuth_base_string 'POST' 'http://api.twitter.com/1/statuses/update.json' ${params[]})

For getting signature, we use OAuth_signature (no prefix underscore), it gets required parameter from global variable, therefore we only need to supply the $base_string.

signature=$(OAuth_signature "$base_string")

3   Additions

System Message: WARNING/2 (<string>, line 123)

Title underline too short.

Additions
========

OAuth.sh actually provides a helper function, you can do it in one line:

header="$(_OAuth_authorization_header 'Authorization' 'http://api.twitter.com/' "$oauth_consumer_key" "$oauth_consumer_secret" '' '' "$oauth_signature_method" "$oauth_version" "$(OAuth_nonce)" "$(OAuth_timestamp)" 'POST' 'https://api.twitter.com/oauth/request_token' "$(OAuth_param 'oauth_callback' 'oob')"), $(OAuth_param_quote 'oauth_callback' 'oob')"

OAuth_nonce and OAuth_timestamp are to generate nonce and timestamp. The last two parts look similar, first OAuth_param is for signing and the second is to add oauth_callback to header string because _OAuth_authorization_header only generate header string for some basic parameters. You will have to put them into header string manually using OAuth_param_quote.

There is also an OAuth_authorization_header, it will generate nonce and timestamp automatically.

If you need to put binary data into signing (I havent seen any API requires that), you can use OAuth_param_file to put percent-encoding encoded file content into the params.

4   Conclusion

OAuth is not really hard to learn. I currently has used this library for Twitter, Twitpic (OAuth Echo2), and stereomood. This post is just a brief introduction of OAuth.sh and I apologize for my bad writing and incompletion, please read sources for more idea. You can start with two clients tcli.sh (Twitter + Twitpic) and Basm.sh (stereomood).

Here are few checkups when doing signing and server tells that you have incorrect signature:

  • HTTP or HTTPS?
  • GET or POST?
  • Have you had all required parameters for signing?
  • Have you put not required parameters for signing?
  • Is URL in signing and URL you actually use curl to request the same?
  • Have you accidentally added some salt to your key, token, and secrets?

This library is not robust, so please use it with care. Any feedback is very welcome.

Happy OAuthing!


[1]Its not the same as urlencode we used to know in other programming language library.
[2]dead link http://mehack.com/oauth-echo-delegation-in-identity-verificatio