Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js + jsOAuth

I'm building a mobile app with Backbone.js and I need to do a two-legged OAuth to connect with a REST API. I found a library called jsOAuth but not sure how to integrate it with Backbone.

Should I rewrite the sync method to include the headers?

Any help would be appreciated.

like image 970
rglasgow Avatar asked Oct 13 '11 22:10

rglasgow


2 Answers

I was able to do this without using jsOAuth. I overrode my model's sync method to make jquery ajax calls, and set the beforeSend attribute on those calls to create an oauth header on the request. Then, after setting the appropriate attributes on the model (body and url, specifically), all you have to do to PUT/POST is modelInstance.save(), and the model takes care of the oauth itself.

The below examples are in coffeescript.

Model sample:

Backbone.Model.extend

    sync: (method, model, options) ->

        switch method
            when "create"
                $.ajax({
                    url: model.url()
                    data: model.body
                    dataType: 'json'
                    cache: false
                    type: 'POST'
                    beforeSend: (xhr, settings) =>
                        auth = @makeAuthHeader(key, secret, settings.url, 'POST', realm)
                        xhr.setRequestHeader('Authorization', auth)
                        xhr.setRequestHeader('Content-Type', 'application/json')
                    success: (data, textStatus) ->
                        model.postSuccess(data, textStatus)
                    error: (e, jqxhr, exception) ->
                        model.postError(e, jqxhr, exception)
                })
            when "update"
                $.ajax({
                    url: model.url()
                    data: model.body
                    …

The 'makeAuthHeader` function:

makeAuthHeader: (key, secret, encodedurl, method, realm) ->
    accessor = {consumerSecret: secret, tokenSecret: ""}
    message = {action: encodedurl, method: method, parameters: [["oauth_version", "1.0"],["oauth_consumer_key", key]]}
    OAuth.setTimestampAndNonce(message)
    OAuth.SignatureMethod.sign(message, accessor)
    return OAuth.getAuthorizationHeader(realm, message['parameters'])

The oauth module I used is the one Netflix created in 2008, which you can find here. In case that gets taken down somehow, you can probably find the file by googling javascript oauth "This isn't as useful as you might hope". That query maybe doesn't sound like an endorsement of the file, but I found it to be untrue: the file is very useful.

Other possible stumbling blocks:

  • Your model will need a url function on it that returns the URL to send the request to.
  • key, secret, and realm get passed in to the initialize method of this model, and so are accessible in the code I've shown above.
  • model.body is an attribute you'll have to set yourself. It's not a backbone-standard attribute.
  • If my example seems a bit off, it's because the model I've shown here is actually one I wrote solely for doing oauth communication. I then had my models that actually contained data extend this model. That's why, for instance, the ajax call's success method calls model.success(). If this model had been a one-off, the ajax call's success method would actually perform the success work right there.
like image 122
dshapiro Avatar answered Oct 06 '22 08:10

dshapiro


I think I may have answered this one on Twitter.

jsOAuth 1.x cant be plugged into jQuery easily and so therefore backbone. However there has been some progress since my answer on Twitter.

jsOAuth 2.0, in development, implements a XHR like interface so that you could use it like this:

jQuery.ajaxSettings.xhr =  function () {
    var xhr =  new OAuthRequest;
    xhr.consumerKey = consumerKey;
    xhr.consumerSecret = consumerSecret;
    xhr.accessTokenKey = accessTokenKey;
    xhr.accessTokenSecret = accessTokenSecret;

    return xhr;
};

As you can see, pushed directly into jQuery as the XHR object it uses.

like image 35
bytespider Avatar answered Oct 06 '22 08:10

bytespider