It was with a certain excitement and dread that I approached the final project. “It is supposed to be your magnum opus — a culmination of
all the skills you’ve learned so far,” they said. “Go wild!…you’re free to add on as much stuff as you’d like,” they said.
The latter endorsement was an invitation to too much fun, with frequent refiguring about how to scale the next coding obstacle. This is what I ended up building:
Snappy Name: We/Mix
Domain: A full CRUD music video playlist builder
Why: Because music drives creativity and it’s fun
I learned so much from doing this project which would encompass more than just one blog post. To begin with, I got to put Test Driven Development and JSON Web Token Authentication into practice. The following are some highlights:
Creating a useful Rails API
Although I’d worked through labs and understood the concepts in their individual parts, I had not yet created an API which could handle CRUD actions. It seemed like the best way to accomplish this was to take a Test Driven Development approach to ensure that I would build what I wanted.
I leaned on Luke’s series of Instructor Videos as guidelines in test buildout and ensuring that my API was coming through as expected. I got a lot of practice using Postman, used only sporadically in API Development labs, and finally became really comfortable using it. I was also introduced to RESTed, another great tool to quickly format and make HTTP requests and view the response.
I was curious about using JSON Web Tokens since it had not been introduced in the course material. Following one of Luke’s aforementioned study group videos for the initial build out on the backend, I dove into the “Wild West” of React Authentication to find my own solution. Here’s a summary of the steps I took to build mine:
Step 1: Implement password hashing and encryption with bcrypt
- Enabled the bcrypt gem in my gemfile for password hashing and encryption and ran
- Created a user migration with :username, :password_digest, and :email attributes
- Going to the user model, enabled
has_secure_passwordto take advantage of ActiveRecord methods that tap into
authenticate). Also added validations for
:usernamepresence and uniqueness.
- Now routes are needed to enable creation of users on signup. In the
config/routes.rbfile, I added the `post ‘/signup’, to: “users#signup”` route
- In the Users Controller,
users_controller.rb, I created the signup method and a private `user_params` to make sure that only permitted parameters are included in User creation.
- I added a Sessions Controller and then wrote a basic
- With both Users and Sessions Controllers set up to encrypt passwords and then authenticate Users, I turned to implementing JWT.
Step 2: Enable coding and decoding of user attributes with JSON Web Tokens
- Added the jwt-gem to my gemfile (JWT info: https://jwt.io/) and ran
- Select a hashing algorithm — I ran with the default, HMAC (HS256)
- I needed methods to create and decode JWT’s. To implement this, I created an
auth.rbfile in the
libfolder, built an `Auth` class, and then built
decode_tokenclass methods according to the video. The
create_tokenmethod takes a User object as an argument and then creates a token associated with it.
- Now to make these methods useful. In the Users Controller, I want to create a token when a user signs up for my app. If a User has saved, then a token would be created at the same time, effectively logging them in at the same time.
- Turning to the Sessions Controller and session creation, the
loginaction receives a user’s email and password and then finds a user by email and authenticated by their password. If both are true, a JWT token is created and sent to the client via JSON.
^If present, comment out
protect_from_forgery_with: :exception line in `application_controller.rb`.
protect_from_forgery exists to protect Rails applications from Cross-Site Request Forgery (CSRF), a serious vulnerability from placing trust on the session identification cookies passed between browser and server. JSON Web Tokens would replace the function of Rails’ default CSRF protections.
On the React side, my goals were to enable Users to
- Login and CRUD their own video playlist
- Prevent other users from seeing their playlist or perform any other action on the User’s account
To accomplish this, I did the following:
- Created LoginPage and SignUpPage Containers.
- I decided that the JWT would be stored in localStorage, which is not in itself connected to the store. Because of this, I decided to place functions involved in Login and Signup We/Mix API calls in an api directory. User sign up, or registration, occurs in a UserApi Class containing a signup function which “POST’s” a new User’s email, username, and password to the
createaction in the Users Controller. User login occurs in a SessionApi Class containing a login function which “POST’s” a User’s credentials to the
loginaction in the Sessions Controller. Both of these calls result in a returned JWT which is then stored in the window’s
- I still wanted to have Session and User actions connected to the store. I did this by
react-redux to both the LoginPage and SignUpPage containers.
(2) setting up a sessionActions file to hold sessions-related action creators. So far, these action creators set the received JWT to localStorage and clear the token from localStorage on logout.
(3) Similarly, I set up a userActions file to hold user-related action creators which set the received JWT to localStorage.
(4) I am still considering adding actions to each of these files and dispatching them to the user_reducer to add an “authenticated” attribute to the store. However, it’s not yet clear that it would be helpful since I’ve successfully implemented an
EnsureLoggedIn wrapper component, which brings me to…
4. Protection from other viewers: The Rails API only sends videos associated to the authorized user in the
index action. I created an
EnsureLoggedIn wrapper component to protect routes unless a user was logged in.
With all of the ideas in my head, I could not have accomplished this without the community at Learn and talking through ideas with friends and instructors. Special thanks go to Luke Ghenco for direction, Alice Balbuena for the invaluable study group and for taking time, and Chris Cole, David Kennell, and Jaci Hayden for their general support. Thank you!!
- Luke Ghenco, “JWT Authentication With Rails,” January 27, 2017
- Sophie DeBenedetto, “JWT Authentication with React + Redux,” September 9, 2016
- Raja Rao DV, “React Redux CRUD App/react-redux-blog,” Accessed November 2017 (Associated blog :Securing React Redux Apps With JWT Tokens)
- Scott Luptowski, “Adding Login and Authentication Sections to your React or React Native app,” Aug 25, 2016