Search code examples
angularjsperlsession-cookiesmojolicious

send mojolicious session cookie with $http in angular app


I'd like GET requests made by angular ($http) to include the session cookie. I though including $httpProvider.defaults.withCredentials = true; was sufficient. Still, no requests include cookies.

I have a mojolicious application serving an angular application. Mojolicious exposes a login API:

  • POST authenticates
  • GET indicates if a session is still valid (returns name with a value if good, null otherwise).

Session cookies need to be included in the GET request. How is this implemented in angular?

» curl localhost:3000/login -d '{"user": "test", "password": "pswd"}' -c cookie.txt
{"login":1,"name":"test"}

» curl localhost:3000/login -b cookie.txt
{"name":"test"}

» curl localhost:3000/login 
{"name":null}

» cat cookie.txt
# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_localhost FALSE   /   FALSE   1414178938  lncddbv3    eyJleHBpcmVzIjoxNDE0MTc4OTM4LCJ1c2VyIjoidGVzdCJ9--7fa22efde0d87e7d79f2d29d7adb97ab92f632c4

Client Side:

<html lang="en">
<head>
  <title>login test</title>
  <script type="text/javascript" src="lib/jquery-1.11.0.min.js"></script>
  <script type="text/javascript" src="lib/angular.js"></script>
  <script type="text/javascript" src="bower_components/angular-cookies/angular-cookies.js"></script>
  <script>
    var URL='http://localhost:3000/';

    angular.module('loginTest',['ngCookies'])
        .config(function($httpProvider) {
          $httpProvider.defaults.withCredentials = true;
        })

    angular.module('loginTest')
      .controller('loginCtrl',function loginCtrl($scope,$http){

         // is our session valid?
         $scope.isvalid = function() {
              $http({
                 url: URL+'login/',
                 method:"GET",
                 headers: {'Content-Type': 'application/json'},
                })
               .success(
                 function(data){
                   console.log('isvalid',data);
                   $scope.validname = data.name;
                });
         };

         // authenticate session
         // call isvalid on success
         $scope.auth = function(){
              $http({
                 url: URL+'login/',
                 method:"POST",
                 headers: {'Content-Type': 'application/json'},
                 dataType: 'json',
                 data: {user: "test", password: "pswd" }
              })
              .success(
                 function(data){
                   console.log('login', data);
                   $scope.authname = data.name;
                   $scope.isvalid()
                 }
              );
            };

       // try both. auth calls valid
       $scope.auth()
      });

  </script>
</head>
<body ng-app="loginTest">
 <div ng-controller="loginCtrl">
   <button ng-click="auth()">auth</button> 
   <button ng-click="isvalid()">valid?</button> <br>
   auth as: "{{authname}}";<br>
   valid as: "{{validname}}"
 </div>
</body>
</html>

As seen in the browser+firebug:

Firebug Output

Auth API:

  ## use angular files
  push @{$self->static->paths}, $self->home->rel_dir('../angular/');

  ## routes
  my $r=$self->routes;
  $r->get ('/login')->to('login#isLogin');
  $r->post('/login')->to('login#login');

  #### Login.pm
  sub login {
   my $self=shift;
   my $json =decode_json($self->req->body || '{}');
   $self->session(user => $json->{user}) 
          if($json->{user} eq "test" && $json->{password} eq "pswd");

  }

  sub isLogin {
   my $self = shift;
   $self->render(json => {name=>$self->session('user') } );
  }

  ####

Solution

  • Use localhost.localdomain or 127.0.0.1 instead of localhost.

    Cookies are sent on all requests for valid domains. A valid domain name requires at least one dot.

    Cookies on localhost with explicit domain