Champer Wu
Champer Wu

Reputation: 1271

Should token store into database in Ruby On Rails?

I use the gem jwtdevise to build a user login system,

I generate a model Authentication to check the token exist or not.

follow this code:

models/authentication.rb

class Authentication < ApplicationRecord
  def self.generate_access_token(email)
    payload = {:email => email}
    secret = 'secret'
    token = JWT.encode payload, secret, 'HS256'
    return token
  end
end

controllers/user/sessions_controller.rb

def create
    user = User.where(email: params[:email]).first
    if user&.valid_password?(params[:password])
      @token = Authentication.generate_access_token(user.email)
      Authentication.create(access_token: @token)
      authentications = {token: @token, email: user.email}
      render json: authentications, status: :created
    else
      head(:unauthorized)
    end
  end

when I do a post request to user/sessions I will get token and user email and store it in localstorage of client, and help me to check the token is valid.

follow this code:

def authenticate_token
  token = Authentication.find_by_access_token(params[:token])
  head :unauthorized unless token
end 

In my question, are there ways to let token don't need to store into database?

Upvotes: 0

Views: 1183

Answers (1)

Aetherus
Aetherus

Reputation: 8898

You can decode the token and get the email stored in it, and find user by that email.

Suppose you carry the token in the Authorization header, like

Authorization: Bearer <token>

then you can define a before_action to do this:

class ApplicationController < ActionController::API
  before_action :authenticate_token

  def authenticate_token
    token = request.headers['Authorization'].to_s =~ /^Bearer (.*)$/i && $1
    return head :unauthorized unless token
    payload = JWT.decode(token, 'secret', true, algorithm: 'HS256')
    user = User.find_by(email: payload['email'])
    return head :unauthorized unless user
    # TODO set the `user` as current_user
    # How to patch devise's `current_user` helper is another story
  end
end

If I were you, I would put user ID in the token, not email, because ID is shorter, and faster to lookup from database, and it exposes nothing personal to the internet (note that JWT is not encrypted. It's just signed).

Or you can skip all these messy things by just using knock instead of devise.

Upvotes: 2

Related Questions