title: Localstorage vs cookies for OAuth2 in HTML5 Web App
body: <p>I am currently experimenting with OAuth2 to develop a mobile application built entirely in JavaScript that talks to a CakePHP API. Take a look at the following code to see how my app currently looks <strong>(please note that this is an experiment, hence the messy code, and lack of structure in areas, etc..)</strong></p>
  <pre><code>var access_token,
       refresh_token;
  
  var App = {
      init: function() {
          $(document).ready(function(){
              Users.checkAuthenticated();
          });
      }(),
      splash: function() {
          var contentLogin = '&lt;input id=&quot;Username&quot; type=&quot;text&quot;&gt; &lt;input id=&quot;Password&quot; type=&quot;password&quot;&gt; &lt;button id=&quot;login&quot;&gt;Log in&lt;/button&gt;';
          $('#app').html(contentLogin);
      },
      home: function() {
          var contentHome = '&lt;h1&gt;Welcome&lt;/h1&gt; &lt;a id=&quot;logout&quot;&gt;Log out&lt;/a&gt;';
          $('#app').html(contentHome);
      }
  };
  
  var Users = {
      init: function(){
          $(document).ready(function() {
              $('#login').live('click', function(e){
                  e.preventDefault();
                  Users.login();
              });
              $('#logout').live('click', function(e){
                  e.preventDefault();
                  Users.logout();
              });
          });
      }(),
      checkAuthenticated: function() {
          access_token = window.localStorage.getItem('access_token');
          if( access_token == null ) {
              App.splash();
          }
          else {
              Users.checkTokenValid(access_token);
          }
      },
      checkTokenValid: function(access_token){
  
          $.ajax({
              type: 'GET',
              url: 'http://domain.example/api/oauth/userinfo',
              data: {
                  access_token: access_token
              },
              dataType: 'jsonp',
              success: function(data) {
                  console.log('success');
                  if( data.error ) {
                      refresh_token = window.localStorage.getItem('refresh_token');
                       if( refresh_token == null ) {
                           App.splash();
                       } else {
                           Users.refreshToken(refresh_token);
                      }
                  } else {
                      App.home();
                  }
              },
              error: function(a,b,c) {
                  console.log('error');
                  console.log(a,b,c);
                  refresh_token = window.localStorage.getItem('refresh_token');
                   if( refresh_token == null ) {
                       App.splash();
                   } else {
                       Users.refreshToken(refresh_token);
                  }
              }
          });
  
      },
      refreshToken: function(refreshToken){
  
          $.ajax({
              type: 'GET',
              url: 'http://domain.example/api/oauth/token',
              data: {
                  grant_type: 'refresh_token',
                  refresh_token: refreshToken,
                  client_id: 'NTEzN2FjNzZlYzU4ZGM2'
              },
              dataType: 'jsonp',
              success: function(data) {
                  if( data.error ) {
                      alert(data.error);
                  } else {
                      window.localStorage.setItem('access_token', data.access_token);
                      window.localStorage.setItem('refresh_token', data.refresh_token);
                      access_token = window.localStorage.getItem('access_token');
                      refresh_token = window.localStorage.getItem('refresh_token');
                      App.home();
                  }
              },
              error: function(a,b,c) {
                  console.log(a,b,c);
              }
          });
  
      },
      login: function() {
          $.ajax({
              type: 'GET',
              url: 'http://domain.example/api/oauth/token',
              data: {
                  grant_type: 'password',
                  username: $('#Username').val(),
                  password: $('#Password').val(),
                  client_id: 'NTEzN2FjNzZlYzU4ZGM2'
              },
              dataType: 'jsonp',
              success: function(data) {
                  if( data.error ) {
                      alert(data.error);
                  } else {
                      window.localStorage.setItem('access_token', data.access_token);
                      window.localStorage.setItem('refresh_token', data.refresh_token);
                      access_token = window.localStorage.getItem('access_token');
                      refresh_token = window.localStorage.getItem('refresh_token');
                      App.home();
                  }
              },
              error: function(a,b,c) {
                  console.log(a,b,c);
              }
          });
      },
      logout: function() {
          localStorage.removeItem('access_token');
          localStorage.removeItem('refresh_token');
          access_token = window.localStorage.getItem('access_token');
          refresh_token = window.localStorage.getItem('refresh_token');
          App.splash();
      }
  };
  </code></pre>
  <p>I have a number of questions relating to my implementation of OAuth:</p>
  <ol>
  <li><p>Apparently storing the access_token in localStorage is bad practice and I should instead be using cookies. Can anyone explain why? As this isn't anymore secure or less secure as far as I can tell, as the cookie data wouldn't be encrypted.</p>
  <p>According to this question: <a href="https://stackoverflow.com/questions/3220660/local-storage-vs-cookies">Local Storage vs Cookies</a> storing the data in localStorage is ONLY available on the client-side anyways and doesn't do any HTTP request unlike cookies, so seems more secure to me, or least doesn't seem to have any issues as far as I can tell!**</p>
  </li>
  <li><p>Relating to question 1, use of a cookie for expiration time, would equally be pointless to me, as if you look at the code, a request is made on app start to get the user info, which would return an error if it had expired on the server end, and require a refresh_token. So not sure of benefits of having expiry times on BOTH client and server, when the server one is what really matters.</p>
  </li>
  <li><p>How do I get a refresh token, without A, storing it with the original access_token to use later, and B) also storing a client_id? I've been told this is a security issue, but how can I use these later, but protect them in a JS-only app? Again see the code above to see how I have implemented this so far.</p>
  </li>
  </ol>