53

My server has a manual authorization. I need to put the username/password of my server to my backbone request inorder for it to go through. How may i do this? Any ideas? Thank you

n0minal
  • 3,195
  • 9
  • 46
  • 71

10 Answers10

56

Models in Backbone retrieve, update, and destroy data using the methods fetch, save, and destroy. These methods delegate the actual request portion to Backbone.sync. Under the hood, all Backbone.sync is doing is creating an ajax request using jQuery. In order to incorporate your Basic HTTP authentication you have a couple of options.

fetch, save, and destroy all accept an additional parameter [options]. These [options] are simply a dictionary of jQuery request options that get included into jQuery ajax call that is made. This means you can easily define a simple method which appends the authentication:

sendAuthentication = function (xhr) {
  var user = "myusername";// your actual username
  var pass = "mypassword";// your actual password
  var token = user.concat(":", pass);
  xhr.setRequestHeader('Authorization', ("Basic ".concat(btoa(token))));
}

And include it in each fetch, save, and destroy call you make. Like so:

 fetch({
  beforeSend: sendAuthentication 
 });

This can create quite a bit of repetition. Another option could be to override the Backbone.sync method, copy the original code and just include the beforeSend option into each jQuery ajax request that is made.

Hope this helps!

Amir Ismail
  • 3,865
  • 3
  • 20
  • 33
shanewwarren
  • 2,234
  • 22
  • 17
  • tried your code. but there's no response. it doesn't call the service. – n0minal Apr 10 '12 at 03:21
  • No response at all? Or are you receiving a 401 response code? – shanewwarren Apr 10 '12 at 04:14
  • 1
    nope. anyways. can you give me a sample code on how to override the backbone.sync to headers? – n0minal Apr 10 '12 at 05:12
  • Can you provide an example of the backbone.js code that you wrote for this implementation? I'm having a problem getting it to work. You can see my progress in [this question](http://stackoverflow.com/questions/14752326/adding-http-basic-authentication-header-to-backbone-js-sync-function-prevents-mo) – MusikPolice Feb 21 '13 at 14:30
  • 2
    I wouldn't copy the original Backbone.sync method. You can do something like what's suggested in http://japhr.blogspot.com/2011/10/overriding-url-and-fetch-in-backbonejs.html, but basically just override `options`, and call `Backbone.Model.prototype.fetch.call(this, options)`. – chug2k Oct 10 '13 at 00:10
43

The easiest way to add request header in Backbone.js is to just pass them over to the fetch method as parameters, e.g.

MyCollection.fetch( { headers: {'Authorization' :'Basic USERNAME:PASSWORD'} } );
tmaximini
  • 8,403
  • 6
  • 47
  • 69
  • This worked for me, surprisingly! And it's not in the docs by the time I'm typing just if anyone wondered. Extremely simple way to handle it ;) amazing. >thanks! – albertpeiro Jun 20 '13 at 12:28
  • 1
    that works unless username has a : in it, you really should base64 encode username:password – dstarh Aug 16 '13 at 20:43
30

One option might be to use the jQuery ajaxSetup, All Backbone requests will eventually use the underlying jQuery ajax. The benefit of this approach is that you only have to add it one place.

$.ajaxSetup({
    headers: { 'Authorization' :'Basic USERNAME:PASSWORD' }
});

Edit 2nd Jan 2018 For complex web applications this may not be the best approach, see comments below. Leaving the answer here for references sake.

Andy Polhill
  • 6,858
  • 2
  • 24
  • 20
  • 1
    While it looks like it could work, **don't use this** for [the reasons I described in another answer](https://stackoverflow.com/a/41991573/1218980). – Emile Bergeron Dec 22 '17 at 06:19
  • 1
    I'd be inclined to agree, my answer is pretty old now. The only thing I would say is if you are working on a simple experiment with one data source this would be a quick way of getting going. So I might leave it here for reference. – Andy Polhill Jan 02 '18 at 13:07
18

You could override Backbone sync method.

#coffeescript
_sync = Backbone.sync
Backbone.sync = (method, model, options) ->
    options.beforeSend = (xhr) ->
        xhr.setRequestHeader('X-Auth-Token_or_other_header' , your_hash_key)
        #make sure your server accepts X-Auth-Token_or_other_header!!
    #calling the original sync function so we only overriding what we need
    _sync.call( this, method, model, options )       
zzart
  • 11,207
  • 5
  • 52
  • 47
11
Backbone.$.ajaxSetup({
    headers: {'Authorization' :'Basic USERNAME:PASSWORD'}
});

This code set headers to Backbone ajax, so they will be sent with every Backbone.sync. You will be able to send headers without using xhr.setRequestHeader with every sync call.

So you don't need to do the following every time:

MyCollection.fetch({ headers: {'Authorization' :'Basic USERNAME:PASSWORD'} } );

You can just do

MyCollection.fetch();

Maybe it's kind of hack but it works perfectly for my system.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Roman Paraschak
  • 175
  • 1
  • 9
  • Perhaps you could give an explanation as to how this answers the question? – Wally Altman Jun 05 '15 at 02:01
  • It is a hack that shouldn't be used for reasons explained in [another answer of mine](https://stackoverflow.com/a/41991573/1218980). It's also the same answer as [the `$.ajaxSetup` one above](https://stackoverflow.com/a/20633326/1218980). – Emile Bergeron Dec 22 '17 at 06:24
  • Is there a way to define the response interceptor? Something like ajaxError? – Ziko Sep 06 '19 at 17:41
6

My approach to something like this would be overwrite the sync method in order to add the header before doing the request. In the example you could see that I'm creating a Backbone.AuthenticatedModel, which extends from Backbone.Model.

This will impact all methods (GET, POST, DELETE, etc)

Backbone.AuthenticatedModel = Backbone.Model.extend({
    sync: function(method, collection, options){
        options = options || {};
        options.beforeSend = function (xhr) {
            var user = "myusername";// your actual username
            var pass = "mypassword";// your actual password
            var token = user.concat(":", pass);
            xhr.setRequestHeader('Authorization', ("Basic ".concat(btoa(token))));
        };
        return Backbone.Model.prototype.sync.apply(this, arguments);
    }

});

Then you have to simple extend the model you need to have authentication, from the Backbone.AuthenticatedModel you have created:

var Process = Backbone.AuthenticatedModel.extend({
    url: '/api/process',

});
sebastian-greco
  • 118
  • 1
  • 5
  • 1
    I like your solution! But in the return line I would call `Backbone.Model.prototype.sync.apply(this, arguments)` instead. – Cristian C. Apr 05 '16 at 11:59
  • @cristian-conedera You are right, that would be a more elegant and correct way. Changed the code as you suggested – sebastian-greco Apr 05 '16 at 12:04
  • 1
    I would just add a call to the original `beforeSend` option (if passed) inside the new beforeSend callback. See the annotated source for reference: http://backbonejs.org/docs/backbone.html#section-179 – Emile Bergeron Jul 06 '16 at 17:07
4
Object.save(
  {'used': true}
  {headers: {'Access-Token': 'access_token'}}
)
  • That's the same answer as the [`fetch` example above](https://stackoverflow.com/a/11846129/1218980), but without any explanation. – Emile Bergeron Dec 22 '17 at 06:29
2

Create a custom sync method that intercepts the calls to Backbone.sync and stuffs your authorization headers in and passes everything else through:

    REPORTING_API_KEY = 'secretKeyHere';
    CustomSync = function(method, model, options) {
        options.headers = {
            'Authorization' : 'Bearer ' + REPORTING_API_KEY
        };
        return Backbone.sync(method, model, options);
    };

Then overwrite your model's sync with that one:

    MyModel = Backbone.Model.extend({
        urlRoot: '/api/',
        sync: CustomSync
    });
ehed
  • 804
  • 1
  • 8
  • 18
  • That's a good way, but instead of overwriting the `sync` function, you should override it and call the parent one which is not guaranteed to be `Backbone.sync`. – Emile Bergeron Dec 22 '17 at 06:28
1

Try to use it. We can use either

beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRFToken', csrf_token);
},

or

headers: {
    "X-CSRFToken": csrf_token
},

But I would recomment the first option(beforeSend).

Here is the working code snippet in my case.

var csrf_token = this.getCSRFToken();
self.collection.fetch(
{
    beforeSend: function(xhr) {
        xhr.setRequestHeader('X-CSRFToken', csrf_token);
    },
    // headers: {
    //     "X-CSRFToken": csrf_token
    // },
    data: {
        "mark_as": "read"
    },
    type: 'POST',
    success: function () {
        if (clickLink) {
            window.location.href = clickLink;
        } else {
            self.unreadNotificationsClicked(e);
            // fetch the latest notification count
            self.counter_icon_view.refresh();
        }
    },
    error: function(){
        alert('erorr');
    }
});
Umar Asghar
  • 3,808
  • 1
  • 36
  • 32
-1
  1. In the client side, add this before any server communication:

    $.ajaxSetup({
        xhrFields: {
            withCredentials: true
        },
        async: true
    });
    
  2. In the server side add these headers (PHP):

    header('Access-Control-Allow-Origin: http://your-client-app-domain');
    header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS");
    header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
    header('Access-Control-Allow-Credentials: true');
    
Tunaki
  • 132,869
  • 46
  • 340
  • 423