bk11425
bk11425

Reputation: 334

Basic HTTP Authentication in Ember Data REST Adapter

Is there a way in Ember.js (and Ember-data) to send credentials to an api that requires Basic HTTP Authentication? I can see how it's done in JQuery here, but don't see any straightforward way to do it in Ember. I thought maybe adding something to the header would work (see below in coffeescript), but no success:

App.AuthAdapter =  DS.RESTAdapter.extend(
    host: 'https://my-api.example.com'
    namespace: 'v1'
    headers:
        "Authorization Basic fooUsername:barPassword"
    ...

Upvotes: 5

Views: 5437

Answers (3)

SntsDev
SntsDev

Reputation: 71

As @gerry3 stated $.ajaxPrefilter is a valid solution.

But if you want to solve a problem of dynamically changing your Headers AFTER an event, for instance, a successful LOGIN attempt, then you need to put more wires. In my case I need to send back a 'Token' Header that is provided by the server after a successful AJAX-login. But, of course, when the user initiates the App he's not logged-in already.

The problem is that once you reopen or extend the RESTAdapter, or define an ajaxPrefilter, even if you're binding it to a value (or localStorage as in my case) the class won't be following the current variable value. It's like a snapshot taken at some moment. So it's useless in my scenario.

I'm following Embercast Client Authentication which is a good start (code available), but instead of jQuery data-fetching I'm using Ember-Data.

So the trick is to observe the token and re-define the ajaxPrefilter as many times as you need it.

tokenChanged: function() {
    this.get('token')=='' ? 
        localStorage.removeItem('token') : 
            localStorage.token = this.get('token');

    $.ajaxPrefilter(function(options, originalOptions, xhr) {
        return xhr.setRequestHeader('Token', localStorage.token);
    });

}.observes('token')

Therefore, when the user logs-in he'll have a valid token and send it in every request to the server via the RESTAdapter.

Hope this helps someone.

Upvotes: 2

gerry3
gerry3

Reputation: 21460

Can you use $.ajaxPrefilter? e.g.

Ember.$.ajaxPrefilter (options) ->
  options.xhrFields = { withCredentials: true }
  options.username = 'fooUsername'
  options.password = 'barPassword'
  true # need to return non-falsy here

Upvotes: 2

Kingpin2k
Kingpin2k

Reputation: 47367

You can extend the default Rest adapter and add a headers hash which will be included in the ajax that's sent.

App.ApplicationAdapter = DS.RESTAdapter.extend(
   headers:
     withCredentials: true
     Authorization: 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
)

Or you could take it a step farther and override the ajax method

App.ApplicationAdapter = DS.RESTAdapter.extend(
  ajax: (url, type, hash) ->
    adapter = this
    new Ember.RSVP.Promise((resolve, reject) ->
      hash = hash or {}
      hash.url = url
      hash.type = type
      hash.dataType = "json"
      hash.context = adapter

      if hash.data and type isnt "GET"
        hash.contentType = "application/json; charset=utf-8"
        hash.data = JSON.stringify(hash.data)

      if adapter.headers isnt `undefined`
        headers = adapter.headers
        hash.beforeSend = (xhr) ->
          forEach.call Ember.keys(headers), (key) ->
            xhr.setRequestHeader key, headers[key]

    hash.success = (json) ->
      Ember.run null, resolve, json

    hash.error = (jqXHR, textStatus, errorThrown) ->
      Ember.run null, reject, adapter.ajaxError(jqXHR)

    Ember.$.ajax hash
  )
)

Upvotes: 3

Related Questions