P0lska
P0lska

Reputation: 471

Can't get Auth0 JWT authentication in Rails 4 working with Knock

I've followed the quick start guide in Auth0 for Rails API here but sending authenticable requests to my Rails API always returns 500. There is a JWT in the header and I believe it is valid because copying it to JWT.io, pasting my private key into the "secret" input, and clicking "secret base64 encoded" shows "verified".

Relevant code below:

Request info:

Request URL:https://railie-p0lska1.c9users.io/api/feedbacks.json
Request Method:POST
Status Code:401 Unauthorized
Remote Address:104.155.203.100:443

Request headers:

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8,fa;q=0.6
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3JhaWxpZS5hdXRoMC5jb20vIiwic3ViIjoiZmFjZWJvb2t8NTA0MjI0NjEzIiwiYXVkIjoidHhKQXJNODhsTnNtcGpSRjBlZGZXZHlnY2gyMGJFb0QiLCJleHAiOjE0ODM2MjAyNzcsImlhdCI6MTQ4MzU4NDI3N30.KePQsrTFjQjIzB6YmxzJcbhMW6by7WIBOpm51viaDZE
Cache-Control:no-cache
Connection:keep-alive
Content-Length:10
Content-Type:application/json;charset=UTF-8
Cookie:c9.live.user.jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjcxNjI5OSIsIm5hbWUiOiJwMGxza2ExIiwiY29kZSI6IjljWWhzZXc2TXhtZkN2WFNGeWl1IiwiaWF0IjoxNDgzNTExMjU1LCJleHAiOjE0ODM1OTc2NTV9.nkeM2LHqibXDqFQ1ZpQ5RseyO3maO5mz8t5ebtnkDUc; c9.live.user.sso=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjcxNjI5OSIsIm5hbWUiOiJwMGxza2ExIiwiaWF0IjoxNDgzNTExMjU1LCJleHAiOjE0ODM1OTc2NTV9.BOxqLKqy6saBOyRjbpccFn8rXTjncW3H_DT2Ysj4vaU; XSRF-TOKEN=cSD1XB8QFAGZFmKWN16R1P%2B1Kwxnyys6cIzOaee02rpkePtyHwuPhmHftQ%2B4YvFvkd3i3BVkvj5z3NLVBk5UEw%3D%3D; _workspace_session=ZEZ6Q2M1aTdFbXA4SzdTc3o2azlnalhmYTR2akVRSGRobFkrUDNwTmlyZ2RPZDdkR0ozamtET2Roa29LMXM4R1h0MUJmZ2lwUHJzWmJKVThOYUxhcjZid1pqZHQzWTRGdmtNZEhjcDZwNWdIN3o5MXcxdnJUUEdCUHhURmlOUE41Uk9ucXY5bkdDUTUzNHo5S3VQSmlnPT0tLXNaakl6S3YzS0VmQmNzZnRBc2NLS3c9PQ%3D%3D--c88551abbcd6419fc848f66f86e9897a5e93ffa8
Host:railie-p0lska1.c9users.io
Origin:https://railie-p0lska1.c9users.io
Pragma:no-cache
Referer:https://railie-p0lska1.c9users.io/en_AU
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
X-XSRF-TOKEN:cSD1XB8QFAGZFmKWN16R1P+1Kwxnyys6cIzOaee02rpkePtyHwuPhmHftQ+4YvFvkd3i3BVkvj5z3NLVBk5UEw==

Server Error:

Started POST "/api/feedbacks.json" for 220.244.244.218 at 2017-01-05 03:08:27 +0000
Cannot render console from 220.244.244.218! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by FeedbacksController#create as JSON
  Parameters: {"data"=>1, "feedback"=>{"data"=>1}}
Completed 500 Internal Server Error in 20ms (ActiveRecord: 0.0ms)

NoMethodError (undefined method `authenticate_user' for #<FeedbacksController:0x007f818327e000>
Did you mean?  authenticate):

feedbacks_controller.rb

class FeedbacksController < ApplicationController

    before_action :authenticate_user

    respond_to :json

    def create
        VisitorRating.create(request_params)
        reply('Thanks for your feedback', :ok)
    rescue
        reply('Unable to save your feedback', :unprocessable_entity)
    end

    private

        def request_params
          params.require(:feedback).permit(:data)
        end

end

user.rb

class User < ActiveRecord::Base
  has_secure_password

  def self.from_token_payload payload
    # Returns a valid user, `nil` or raise
    # e.g.
    #   self.find payload["sub"]
  end
end

schema.rb

  create_table "users", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string   "auth_id"
  end

  create_table "visitor_ratings", force: :cascade do |t|
    t.integer  "data",       null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

I changed some variables in Knock's knock.rb config file as per this post in Auth0's forum.

Knock.setup do |config|

  config.current_user_from_token = -> (claims) { User.find_or_create_by(auth_id: claims['sub']) }

  config.token_audience = -> { Rails.application.secrets.auth0_client_id }

  config.token_secret_signature_key = -> {
      secret = Rails.application.secrets.auth0_client_secret
      secret += '=' * (4 - secret.length.modulo(4))
      Base64.decode64(secret.tr('-_', '+/'))
    }

end

Part of application_controller.rb

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  before_action :authenticate, only: :testie

  protect_from_forgery with: :exception

  respond_to :json

  # Knock is used for user JWT requests
  include Knock::Authenticable

  def angular
    render 'layouts/application'
  end

  private

    def reply(message, status)
      respond_to do |format|
        format.json  { render :json =>  {:message => message}, status: status}
      end
    end

end

After writing this, I think the problem may have to do with the VisitorRating model not currently belonging to the User model, but I'm new to Rails and not sure about the details.

Upvotes: 3

Views: 878

Answers (1)

zlotnika
zlotnika

Reputation: 56

I assume your app was created after December 6. If so, your config/initializers/knock.rb should look like

Knock.setup do |config|
  config.token_audience = -> { Rails.application.secrets.auth0_client_id }
  config.token_secret_signature_key = -> { Rails.application.secrets.auth0_client_secret }
end

Note that the token secret is not base64 encoded: https://github.com/nsarno/knock/issues/149 and https://github.com/nsarno/knock/issues/146

It also looks like your app/models/user.rb should be something like

class User < ApplicationRecord
  def self.from_token_payload(payload)
    self.find_or_create_by(auth_id: payload['sub'])
  end
end

Your user shouldn't have a password, but the from_token_payload needs to actually get the user from that payload.

Other than that, just make sure you remove duplication of stuff in the controllers (probably don't before_action :authenticate in the app/controllers/application_controller.rb).

Upvotes: 4

Related Questions