Welcome to the first lesson of our course, "Securing and Testing Your Ruby on Rails App." Today, we'll be focusing on user authentication, ensuring user passwords are stored securely using Bcrypt and managing authentication with JWT (JSON Web Tokens).
Authentication is a cornerstone of application security, protecting user data, and controlling access to specific parts of your app. Bcrypt
is a proven library for securely hashing and storing passwords, making it computationally difficult for attackers to crack them. JWTs
enable secure transmission of information as a JSON object, facilitating robust authentication management. By the end of this lesson, you'll be equipped to integrate JWT-based authentication in your Ruby on Rails app.
Let's dive right in!
First, we need to create a User
model to store user information, including their securely hashed passwords. This model will encapsulate user-related data and behaviors.
Run the following Rails generator command to create the User
model with username
and password_digest
fields:
Bash1rails generate model User username:string password_digest:string 2rails db:migrate
Explanation:
rails generate model User username:string password_digest:string
command creates a new User
model with username
and password_digest
attributes.rails db:migrate
command applies the migration, creating the users
table in the database with the specified attributes.With the User
model in place, we'll add password hashing functionality using the has_secure_password
method provided by Rails.
Open the user.rb
model file (app/models/user.rb
) and add the following:
Ruby1class User < ApplicationRecord 2 has_secure_password 3end
Explanation:
class User < ApplicationRecord
: Defines the User
model, inheriting from ApplicationRecord
.has_secure_password
: Uses metaprogramming to add functionalities for securely hashing and storing passwords. It automatically adds attributes like password
and password_confirmation
to the model, managed in-memory for security purposes.Now, whenever you create a new user, the has_secure_password
method will ensure the password is hashed using Bcrypt
and stored in the password_digest
field.
Next, let's implement the register
action in the AuthenticationController
, which will handle the creation of new users.
Here’s the code for the register
action:
Ruby1class AuthenticationController < ApplicationController 2 def register 3 user = User.new(user_params) 4 if user.save 5 render json: { message: 'User created successfully' }, status: :created 6 else 7 render json: { error: user.errors.full_messages }, status: :unprocessable_entity 8 end 9 end 10 11 private 12 13 def user_params 14 params.require(:user).permit(:username, :password) 15 end 16end
Explanation:
register
action creates a new User
object with the provided parameters.created
status.unprocessable_entity
status.user_params
method ensures only permitted parameters (username
and password
) are allowed for user creation.JWTs provide a robust solution for managing authentication. We'll create a token that can be sent to the client and used to verify user identity in subsequent requests. A token is a string of characters that represents a user's authentication credentials. In JWT, tokens contain user information like IDs and expiration dates, and they are securely signed to ensure authenticity. This allows users to authenticate and be recognized without the server having to store session data.
Here's how to set up the generate_token
method in the AuthenticationController
:
Ruby1private 2 3def generate_token(user_id) 4 JWT.encode({ user_id: user_id }, Rails.application.credentials.secret_key_base) 5end
Explanation:
generate_token
method takes a user_id
as an argument.JWT.encode
method to create a token, encoding the user_id
with a secret key (Rails.application.credentials.secret_key_base
).Finally, let’s implement the login
action to authenticate a user and generate a JWT token if the credentials are valid.
Here’s the code for the login
action:
Ruby1def login 2 user = User.find_by(username: params[:username]) 3 if user&.authenticate(params[:password]) 4 token = generate_token(user.id) 5 render json: { token: token }, status: :ok 6 else 7 render json: { error: 'Invalid credentials' }, status: :unauthorized 8 end 9end
Explanation:
login
action finds a user by the provided username
.authenticate
method verifies the password.generate_token
method and returns it in the JSON response with a ok
status.unauthorized
status.Lastly, register the new actions in the routes.rb
file:
Ruby1Rails.application.routes.draw do 2 post 'register', to: 'authentication#register' 3 post 'login', to: 'authentication#login' 4 resources :todos 5end
In this lesson, we covered:
User
model and securing passwords with has_secure_password
.register
action to create new users.generate_token
method.login
action to authenticate users and provide a JWT token.By achieving these tasks, you've secured your Ruby on Rails application using JWT for authentication. Now, move on to the practice exercises to further solidify your understanding. Great job!