Authentication with Vanilla JS front-end and Rails back-end

Sbb3391
3 min readJul 15, 2021

We’re on the homestretch of the Flatiron Journey. Mod4 was the coming together of the user experience and the server sides. It was a satisfying experience to put together a full stack project that looks and feels like what a user of the modern internet might experience.

There were many hurdles throughout the project. This article will look in detail at one the new challenges I experienced — authentication beyond the Rails.

Rails comes standard with some great features and middleware to enable user authentication (who is using my app?), and many useful addons like bycrypt. Rails uses special session cookies to keep track of an app’s logged-in state (remember http requests are stateless). Any time a user makes a request to the server, it included the session cookie, which includes a hash containing a secure token used to securely verify who’s using the application.

It’s all very straightforward when using Rails as your backend and Rails views as your frontend. Using a Rails API with a Javascript user interface becomes a little more challenging. When initiating a Rails API repo, much of the middleware and configuring needed for sessions to function are not included. It got the point where another solution was needed. JSON Web Tokens (JWT) were the answer.

I will explain what a JSON Web Token is and an overview of the logic used in my project.

What is a JSON Web Token?

Similar in many ways to a session, a JWT is an object passed from a browser to a server to securely determine logged-in state. Using the token verifies who a user says he is. When a user successfully logs in, a secure access token is returned and stored. Whenever the user requests data from a web-api or other resource that token is submitted as a request header and used to ensure data is shared only with the right parties.

Functionality: Project Example

In my Mod4 Project, users are required to be signed in before having access to any of the app’s features. As described above, my rails backend issues a JWT on successful login, or when a new account is created:

payload = {user_id: user.id}token = encode_token(payload)user_json = UserSerializer.new(user).serializable_hashuser_json[:jwt] = tokenrender json: {user: user_json,jwt: token}

Notice at the bottom “token” is included in the rendered object that is being returned to the browser. Much of the logic is abstracted to helpers and is beyond the scope of this article, but ultimately the secure token returned to the browser and add the token to “localStorage”, which is a browser window function. It is recalled from storage when the user makes different requests to make sure the requested recources are authorized for this user.

Implementation

The following is a rough overview of what is required for implementing JSON Web Tokens.

Rails

  1. install jwt gem
  2. add JsonWebToken class (./lib/json_web_token.rb) which handles the encoding and decoding logic.
  3. add helper methods to ApplicationController
  4. add SessionsController to use the helpers in ApplicationController to render a secure token if all authorization criteria are met. If not, an error message will be rendered letting.

JS

  1. Write function to determine if a user is currently logged into the application:
function determineIfLoggedIn() {const token = localStorage.tokenif (token) {fetch("http://localhost:3000/sessions/autologin", {method: "GET",headers: {'Content-Type': 'application/json','Authorization': `Bearer ${token}`}}).then(resp => resp.json()).then(function(json) {showUserLoggedIn(json.data)document.querySelector("#highlight-buttons-div").classList.remove("hidden")showChooseMascotButton()})} else {forceUserLogin();}}

This function determines if someone is logged into the application localStorage.token === true. If true, it sends a fetch request including the token as a header. The rails backend handles the authorization from there. If no one is logged in, the program requires a successful login or new account creation to proceed.

--

--