How to store authentication bearer token in browser cookie using AngularJS

45,007

Solution 1

There is a $cookies service available in the AngularJS API using the ngCookies module. It can be used like below:

function controller($cookies) {
    //set cookie
    $cookies.put('token', 'myBearerToken');

    //get cookie
    var token=$cookies.get('token');

    //remove token
    $cookies.remove('token');
}
controller.$inject=['$cookies'];

For your case it would be:

//inject $cookies into controller
$scope.GetAuthorizeData = function () {
    $http({
        method: 'GET',
        url: "/api/Values",
        headers: { 'authorization': 'bearer <myTokenId>' },
    })
    .success(function (data) {
        $cookies.put('token', data);
    }).error(function () {
        alert("Failed :(");
    });
};

You will also have to add the angular-cookies module code. And add it to your angular app: angular.module('myApp', ['ngCookies']);. Docs for Angular Cookies.

I would also like to suggest the usage of a Http interceptor which will set the bearer header for each request, rather than having to manually set it yourself for each request.

//Create a http interceptor factory
function accessTokenHttpInterceptor($cookies) {
    return {
        //For each request the interceptor will set the bearer token header.
        request: function($config) {
            //Fetch token from cookie
            var token=$cookies.get['token'];

            //set authorization header
            $config.headers['Authorization'] = 'Bearer '+token;
            return $config;
        },
        response: function(response) {
            //if you get a token back in your response you can use 
            //the response interceptor to update the token in the 
            //stored in the cookie
            if (response.config.headers.yourTokenProperty) {
                  //fetch token
                  var token=response.config.headers.yourTokenProperty;

                  //set token
                  $cookies.put('token', token);
            }
            return response;
        }
    };
}
accessTokenHttpInterceptor.$inject=['$cookies'];

//Register the http interceptor to angular config.
function httpInterceptorRegistry($httpProvider) {
    $httpProvider.interceptors.push('accessTokenHttpInterceptor');
}
httpInterceptorRegistry.$inject=['$httpProvider'];

//Assign to module
angular
    .module('myApp')
    .config(httpInterceptorRegistry)
    .factory('accessTokenHttpInterceptor', accessTokenHttpInterceptor)

Having the http interceptor in place you do not need to set the Authorization header for each request.

function service($http) {
    this.fetchToken=function() {
        //Authorization header will be set before sending request.
        return $http
            .get("/api/some/endpoint")
            .success(function(data) {
                 console.log(data);
                 return data;
            })
    }
}
service.$inject=['$http']

As stated by Boris: there are other ways to solve this. You could also use localStorage to store the token. This can also be used with the http interceptor. Just change the implementation from cookies to localStorage.

function controller($window) {
    //set token
    $window.localStorage['jwt']="myToken";

    //get token
    var token=$window.localStorage['jwt'];
}
controller.$inject=['$window'];

Solution 2

I would advise against keeping the data in a cookie, for security purposes you should set the cookies to secure and HttpOnly (not accessible from javascript). If you're not using SSL, I would suggest moving to https.

I would pass the token from the auth endpoint in a json response:

{
    tokenData: 'token'
}

You can save the token data in sessionStorage by using the $window service:

$window.sessionStorage.setItem('userInfo-token', 'tokenData');

It will be cleared once the user closes the page, and you can manually remove it by setting it to empty string:

$window.sessionStorage.setItem('userInfo-token', '');

Edit:

Interceptor implementation for catching data, adapted from cbass (not tested, you can inspect the objects for response/request to fiddle with the information):

//Create a http interceptor factory
function accessTokenHttpInterceptor($window) {
    return {
        //For each request the interceptor will set the bearer token header.
        request: function($config) {
            //Fetch token from cookie
            var token=$window.sessionStorage.getItem('userInfo-token');

            //set authorization header
            $config.headers['Authorization'] = 'Bearer '+token;
            return $config;
        },
        response: function(response) {
            //if you get a token back in your response you can use 
            //the response interceptor to update the token in the 
            //stored in the cookie
            if (response.config.url === 'api/token' && response.config.data.tokenData) {
                  //fetch token
                  var token=response.config.data.tokenData;

                  //set token
                  $window.sessionStorage.setItem('userInfo-token', token);
            }
            return response;
        }
    };
}

accessTokenHttpInterceptor.$inject=['$window'];
Share:
45,007
Bimal Das
Author by

Bimal Das

I am a committed and hard working individual who enjoys a challenge. In addition to strong communication skills, I am able to work effectively in a team. I can also demonstrate advanced problem-solving skills and thrive under pressure. My drive and ambition ensure I am a valuable addition to any company.

Updated on July 26, 2022

Comments

  • Bimal Das
    Bimal Das almost 2 years

    I have created a bearer token using ASP.net Identity. In AngularJS I wrote this function to get authorized data.

    $scope.GetAuthorizeData = function () {
      $http({
        method: 'GET',
        url: "/api/Values",
        headers: { 'authorization': 'bearer <myTokenId>' },
      }).success(function (data) {
        alert("Authorized :D");
        $scope.values = data;
      }).error(function () {
        alert("Failed :(");
      });
    };
    

    So I want to store this token into Browser cookies. If this token is present there , then take the token and get the data from IIS server Otherwise redirect to login page to login to get a new token.

    Similarly, if user click onto log out button, it should remove the token from browser cookie.

    How to do this ? It it possible ? Is it proper way to authenticate and authorize a user ? What to do if there are multiple users token ?

  • Bimal Das
    Bimal Das over 8 years
    Thanks a lot. I have not tried $window yet in angular JS.Neither have any idea to use SSL. Where should I write these codes? Can you give me more clear answer .
  • Boris
    Boris over 8 years
    You can put the handlers for session storage in a service, or like cbass mentions below using a httpInterceptor.
  • Bimal Das
    Bimal Das over 8 years
    Ya.Got it. Thank you. Nice explanation.
  • goflo
    goflo over 7 years
    Saving the token in the session storage means also that if I open a link in a new tab the token from the session storage isn't available. The user would need to authenticate again (on every tab) which is really annoying. Possible solution: stackoverflow.com/a/32766809/1878249
  • Boris
    Boris over 7 years
    @goflo that's right depending on how the new tab gets opened (it must be a new browsing context so the sessionStorage is not shared). The fallback with localStorage would be useful for such a case. Another alternative with using window.name to keep the data which I find a questionable technique and would consider a last resort. That being said I didn't experience any issue with opening new tabs in my app. But I may have had a slightly different configuration than described above (it's been more than six months since I've touched that code).
  • Kavipriya
    Kavipriya about 7 years
    Hello, where will <myTokenId> be? where to find it?