Before you go, check out these stories!

0
Hackernoon logoAn SPA GUI Session as a Non-HttpOnly Cookie by@Bassaganas

An SPA GUI Session as a Non-HttpOnly Cookie

Author profile picture

@BassaganasJordi Bassagañas

Hi there! How are you today? I write about all things web and more.

Are you writing a single page application or SPA? If so, you'd probably want to store some session data in the user's browser in order to keep track of the GUI's state.

A common scenario is an API dealing with access control rules (ACL) where the frontend needs to do something specific according to the current user's role; for example, display a certain component to admin users only.

Today I'd like to introduce to you an interesting concept which I call the GUI session.

Be aware, GUI session data, which is stored in the browser, cannot ever contain sensitive data such as a password or an authorization token because the GUI session must be read by our JavaScript code.

It doesn't really matter if an attacker is able to gain access to it, the GUI session is saved in the user agent through one of the following mechanisms:

localStorage
,
sessionStorage
, or an HTTP cookie.

Now let me show you a particular implementation based on HTTP cookies as well as React, PHP and Laravel code -- please visit this GitHub repo for further details.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AuthController extends Controller
{
    const COOKIE_ACCESS_TOKEN = 'access_token';
    const COOKIE_SESSION = 'session';

    public function login()
    {
        $credentials = request(['email', 'password']);

        if (!$token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        $session = [
            'role' => auth()->user()->getAttributes()['role'],
        ];

        return response(null, 204)
            ->cookie(self::COOKIE_ACCESS_TOKEN, $token, 480)
            ->cookie(self::COOKIE_SESSION, json_encode($session), 480, null, null, null, false);
    }

    public function logout()
    {
        $accessTokenCookie = \Cookie::forget(self::COOKIE_ACCESS_TOKEN);
        $sessionCookie = \Cookie::forget(self::COOKIE_SESSION);

        return response(null, 204)
                    ->withCookie($accessTokenCookie)
                    ->withCookie($sessionCookie);
    }
}

As you can see this is a basic authentication controller written with PHP; if successfully logged in, the server will send two cookies to the browser:

access_token
and
session
.

Figure 1. Login page

The former is a JWT authentication token, which is an

HttpOnly
cookie because this is sensitive data to be protected from XSS attacks. However the latter is the GUI session, and its very nature is non-HttpOnly because we do want it to be read by our JavaScript code.

Figure 2. The user's role (admin) is stored in the GUI session cookie

As you probably know when manually refreshing URLs in a React app using

BrowserRouter
, all requests are often redirected to
index.html
and therefore the client session is lost.

It is up to the programmer to make both server-side and client-side routing work together nicely.

With the basic Laravel authentication server above, up and running, now we are in a position to write a simple custom ES6 class to just wrap the GUI session, as it is described next.

import Cookies from 'js-cookie';

const name = 'session';

export default class Session {
  static get() {
    if (Cookies.get(name)) {
      return JSON.parse(Cookies.get(name));
    }
    return {
      role: null
    };
  }
}

The

Session
class has multiple purposes, for example with it our React app will be able to make decisions such as loading CASL rules every time a page is refreshed.

import ability from './ability';
import abilityRules from '../../storage/ability-rules.json';
import Session from './Session.js';

...

if (Session.get()) {
  ability.update(abilityRules[Session.get().role]);
}

...

Conclusion

Today we learned how to persist the state of a graphical user interface in a single-page application dealing with an access control list (ACL).

We went through a particular implementation based on HTTP cookies, React and Laravel.

If the user is successfully logged in, the authentication server sends two cookies to the user's browser:

access_token
and
session
. The former is an
HttpOnly
JWT token; the latter is the so-called GUI session sent as a non-HttpOnly cookie.

No sensitive information is saved in the GUI session.

The GUI session is helpful to make smart decisions concerning the graphical user interface such as displaying certain components to certain roles only.

Please visit this GitHub repo for further details.

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.