paul88
paul88

Reputation: 51

How do I limit access to controller methods to only authenticated users with devise?

I have a basic devise question. I have followed a guide to help with user authentication using devise and JWT. Now that the authentication works, I have started to create more models and controllers for other aspects of the app. For example, I have a transactions model and corresponding controller:

class TransactionsController < ApplicationController

  def create
    transaction = Transaction.new(transaction_params)

    if transaction.save
      render json: transaction
    else
      render json: { errors: "transaction is invalid" }, status: :unprocessable_entity
    end
  end

  def index
    transactions = Transaction.all.order(created_at: :desc)
    render json: transactions
  end

  def destroy
    transaction = Transaction.find(params[:id])
    transaction&.destroy
    render json: { message: "transaction deleted"}
  end

  def transaction_params
    params.require(:transaction).permit(:payer_id, :recipient_id, :amount)
  end
end

I added this to the routes like so:

Rails.application.routes.draw do
  devise_for :users,

  controllers: {
      registrations: :registrations,
      sessions: :sessions
  }

  resources :transactions

  root 'homepage#index'
  get '/*path' => 'homepage#index'
end

When testing with Postman, the basic transactions CRUD methods work, but the problem is that shouldn't they only work if the authentication token is provided? I believe that is the point of token based auth, that the token is to be provided in the header with every api request. How do I configure the transaction controller/routes to properly secure each request?

Here is my ApplicationController for reference:

class ApplicationController < ActionController::API

  respond_to  :json

  before_action :process_token


  def authenticate_user!(options = {})
    head :unauthorized unless signed_in?
  end

  def signed_in?
    @current_user_id.present?
  end

  def current_user
    @current_user ||= super || User.find(@current_user_id)
  end

  def process_token
    if request.headers['Authorization'].present?
      begin
        jwt_payload = JWT.decode(request.headers['Authorization'].split(' ')[1].remove('"'), Rails.application.secrets.secret_key_base).first
        @current_user_id = jwt_payload['id']
      rescue JWT::ExpiredSignature, JWT::VerificationError, JWT::DecodeError
        head :unauthorized
      end
    end
  end


end

Upvotes: 1

Views: 863

Answers (1)

r4cc00n
r4cc00n

Reputation: 2137

All you should need to do is add the line below to your ApplicationController: before_action :authenticate_user!

If you want to let some request to pass in a certain controller then you can do: skip_before_action :authenticate_user!

Upvotes: 3

Related Questions