Fast Tricks

Authentication to a RESTful web service in an AngularJS web app

, , 16 Comments

Last week I wrote about how to contact a RESTful web service in an AngularJS web application using the $resource service.
This post is meant to go deeper to an aspect that in that post I just forget to cover, and I have to thank codedungeon, for his comment. This post is about how to deal with web services which require a sort of authentication.

Why to use http headers

Since RESTful paradigm is stateless we cannot manage authentication through sessions, and in general we won’t save on the web server any data about the state of the client. So, each requests have to carry with them the state of the client. For this reason the state of the client is stored as an header of the request itself.

Custom headers with $http

Since AngularJS $resource is built upon the $http service, I want to start the post showing how to set a custom header using the simple $http service.
In this case there are two ways to proceed.
When we want that our custom header is appended to each xhr requests, which is made from the application, we can just add our new header to the array of the default headers.


// Define a new http header
$http.defaults.headers.common['auth-token'] = 'C3PO R2D2';

// It will be used for each new xhr request

In a real world scenario the authentication token is returned from the server, so the previous snippet probably should be used as callback of a login procedure. Time ago I wrote a more generic post about user authentication, and most of the information contained in that post could be useful also in this case.
We can change really a few of the previous snippet, to have an header used only for a particular type of xhr request.


$http.defaults.headers.delete = {};
$http.defaults.headers.delete ['auth-token'] = 'C3PO R2D2';

// It will be used for each new xhr 'delete' request
// Easy!

In this case since $resource (again) is built upon $http, and since we are writing inside $http.defaults, the headers which we set will be used also in the xhr requests that we made through the $resource service… and this is Great!
Another possibility is that we need to set a custom header only for a particular xhr request (and not for all).
In this case the best way to proceed is to use the headers property of the configuration object passed as parameter of the methods of the $http service. Just to make a simple example:


$http.get('books', {
	headers: { 'auth-token': 'C3PO R2D2' },
	params: { bookId: 42 }
}).success(function() { 
	// Be happy! 
});

The header that I set in this way will affect just this xhr request, and won’t be present in all the others.

Custom headers with $resource

In my opinion the best things about the $resource service is the possibility to define our custom request methods.
In my previous post I defined the loan method:


return $resource( '/book/:bookId', 
	{ bookId: '@bookId' }, { 
		loan: { 
			method: 'PUT', 
			params: { bookId: '@bookId' },
			isArray: false 
		} 
	} );

Sadly I don’t know a simple way to set a custom header only for a $resource custom xhr request, using a version of AngularJS prior than 1.2rc1. If you are aware of it I will be happy to read the explanation of your approach in the comments, or to link your explanation.
… However if you’ve already embraced the future, and ported your web application to the last version of AngularJS, there is really a simple way to set the custom header of each of your xhr requests. In this case the previous snippet will become:


return $resource( '/book/:bookId', 
	{ bookId: '@bookId' }, { 
		loan: { 
			method: 'PUT', 
			params: { bookId: '@bookId' },
			isArray: false,
			/* Note the headers property */
			headers: { 'auth-token': 'C3PO R2D2' }
		} 
	} );

Conclusion

In conclusion, as said there many ways to set custom headers, and we have just to understand which one is the better fit for the needs of the web application we are building.

Bruno

I'm Bruno Scopelliti, web developer from Bologna, Italy. I use this space to share my experiences, experiments and thoughts. I'm also on Google+, Twitter, and LinkedIn.

More Posts

Standard
  • Sascha Krause

    Hi Bruno. Thanks for that article. I really enjoy reading your posts.

    But I got one question: is there some kind of best practice of how to receive the authentication token?
    I understand the communication workflow after the user is logged in, but I can’t come up with a “secure” solution to authenticate a user during login process.

    Once a user has entered a username and a password to log in, I would send a POST request to the “backend server” with the users credentials as parameters (in order to receive the authentication token). But isn’t that just “bad” (as one could just spy the network communication and catch the credentials)?

    • http://www.codesimple.ca/ Carl Letourneau

      This is why you should use HTTPS for your communication (at least where the credentials/token are passed).

      One of the reason the token is used afterwards is that you don’t want the client app to maintain the credentials locally (which can be easily read if someone has access to your computer while you are away). Usually the token has some expiration time and/or some validation it comes from the same client (i.e. IP address)

      • Sascha Krause

        Hi Carl,

        Thanks for the info.
        I know about HTTPS and its features. But an REST service can be accessed by a lot of other kindes of services. In my specific case, I want to communicate with this REST service from a Chrome Extension. As far as I know there is no way to send data out of a Chrome Extension via HTTPS. Therefore, the credentials during the login process would be send clear.
        And this just seems bad to me.

  • codedungeon

    Well, this article surely makes sense… However, if the API is expect username:password (as constructed in a typical cURL) how would I send this information from within AngularJS? The receiving API performs basic authentication. When I perform my request, it displays the standard basic authentication dialog (I dont want that to happen, I want to supply these credentials within the $http request)

    • http://www.trajano.net/ Archimedes Trajano

      I’m actually trying to attempt the same thing. I was wondering if I can have as part of my Angular JS app managing the user ID password on their end and prepend username:password to the URL of the REST API service.

  • codedungeon

    I believe I may have found a solution to my problem. Came across the following article and it appears to do what I need. I will do some more testing, but I believe I have found a solution.

    http://wemadeyoulook.at/en/blog/implementing-basic-http-authentication-http-requests-angular/

  • Camilo Lopes

    good post. I have developed webapps with angularjs using restful with java in back-end. I have an example of ebook-store https://github.com/camilolopes/workspaceAngularJs/tree/master/ebookcommerce-parent version live is here: http://apps.camilolopes.com.br/ebookcommerce/

  • Chris

    Hi Bruno,

    Excellent article, but how would you store the authentication token securely? (So that the user doesn’t have to log in every time after he/she closes the browser)

    Tnx,

    Chris

    • Samuel Alejandro Zaragoza Moya

      You have to persist it with local or session storage, that’s my guess :)

  • Silvio Troia

    it doesn’t work … do you know why?
    return $resource(
    ‘http://localhost:8080/Project/rest/secure/Buf’,
    {buf:’@buf’}, {
    post: {
    method: ‘POST’,
    params: {buf:’@buf’},
    isArray: false,
    /* Note the headers property */
    headers: { ‘Content-Type': ‘multipart/form-data’ }
    }
    });

  • http://www.myocart.com Mayoc

    I also want to know about the storage of the authentication token in a secure manner?

  • Fire

    Hi there, has anyone implemented this approach in yii? if so, what links might you have?

  • rupesh oyasis

    Great article………Thanks for sharing.
    http://oyasisspring.com

  • Subrat Sarangi

    Hi Bruno
    very good article on http restFul web service.

    I am using pintrest web service for my project

    And previously i have used jQuery and in ajax call there is a before send property where i give the authontication request like

    /*beforeSend: function(xhr)
    {
    xhr.setRequestHeader(“X-Mashape-Authorization”, _mashapeKey); // Enter here your Mashape key
    }

    */

    But i need this authorization in angularJs
    so in my responsePromise i send the request like this

    /*var _responsePromise = $http({
    method: ‘POST’,
    url: _fetchPinterestPhotosURL,

    headers: { ‘Content-Type': ‘application/x-www-form-urlencoded’,

    ‘X-Mashape-Authorization’ : _mashapeKey

    }

    });

    return _responsePromise;

    */

    But unable to get any response.

    Any help .

    Thank you

    • Subrat Sarangi

      Its working fine. No error in code. Its due to i have installed cross-domain-allow extension in chrome.
      Thank you