Giter Site home page Giter Site logo

knock's Introduction

DISCLAIMER

This project is not being maintained and I don't recommend using it in its current form. As an alternative, I recommend using the jwt gem directly.

knock

Gem Version Build Status Code Climate

Seamless JWT authentication for Rails API

Description

Knock is an authentication solution for Rails API-only application based on JSON Web Tokens.

Getting Started

Installation

Add this line to your application's Gemfile:

gem 'knock'

Then execute:

$ bundle install

Requirements

Knock makes one assumption about your user model:

It must have an authenticate method, similar to the one added by has_secure_password.

class User < ActiveRecord::Base
  has_secure_password
end

Using has_secure_password is recommended, but you don't have to as long as your user model implements an authenticate instance method with the same behavior.

Usage

Include the Knock::Authenticable module in your ApplicationController

class ApplicationController < ActionController::API
  include Knock::Authenticable
end

You can now protect your resources by calling authenticate_user as a before_action inside your controllers:

class SecuredController < ApplicationController
  before_action :authenticate_user

  def index
    # etc...
  end

  # etc...
end

You can access the current user in your controller with current_user.

If no valid token is passed with the request, Knock will respond with:

head :unauthorized

You can modify this behaviour by overriding unauthorized_entity in your controller.

You also have access directly to current_user which will try to authenticate or return nil:

def index
  if current_user
    # do something
  else
    # do something else
  end
end

Note: the authenticate_user method uses the current_user method. Overwriting current_user may cause unexpected behaviour.

You can do the exact same thing for any entity. E.g. for Admin, use authenticate_admin and current_admin instead.

If you're using a namespaced model, Knock won't be able to infer it automatically from the method name. Instead you can use authenticate_for directly like this:

class ApplicationController < ActionController::Base
  include Knock::Authenticable

  private

  def authenticate_v1_user
    authenticate_for V1::User
  end
end
class SecuredController < ApplicationController
  before_action :authenticate_v1_user
end

Then you get the current user by calling current_v1_user instead of current_user.

Configuration

In the entity model

The entity model (e.g. User) can implement specific methods to provide customization over different parts of the authentication process.

  • Find the entity when creating the token (when signing in)

By default, Knock tries to find the entity by email. If you want to modify this behaviour, implement within your entity model a class method from_token_request that takes the request in argument.

E.g.

class User < ActiveRecord::Base
  def self.from_token_request request
    # Returns a valid user, `nil` or raise `Knock.not_found_exception_class_name`
    # e.g.
    #   email = request.params["auth"] && request.params["auth"]["email"]
    #   self.find_by email: email
  end
end
  • Find the authenticated entity from the token payload (when authenticating a request)

By default, Knock assumes the payload as a subject (sub) claim containing the entity's id and calls find on the model. If you want to modify this behaviour, implement within your entity model a class method from_token_payload that takes the payload in argument.

E.g.

class User < ActiveRecord::Base
  def self.from_token_payload payload
    # Returns a valid user, `nil` or raise
    # e.g.
    #   self.find payload["sub"]
  end
end
  • Modify the token payload

By default the token payload contains the entity's id inside the subject (sub) claim. If you want to modify this behaviour, implement within your entity model an instance method to_token_payload that returns a hash representing the payload.

E.g.

class User < ActiveRecord::Base
  def to_token_payload
    # Returns the payload as a hash
  end
end
  • Token Lifetime

By default the generated tokens will be valid, after generated, for 1 day. You can change it in the Knock configuration file (config/knock.rb), setting the desired lifetime:

E.g.

  Knock.token_lifetime = 3.hours

If you are generating tokens for more than one entity, you can pass each lifetime in a hash, using the entities class names as keys, like:

E.g.

  # How long before a token is expired. If nil is provided,
  # token will last forever.
  Knock.token_lifetime = {
    user: 1.day
    admin: 30.minutes
  }

In the initializer

Read lib/knock.rb to learn about all the possible configuration options and their default values.

You can create an initializer like in the example below:

Inside config/initializers/knock.rb

Knock.setup do |config|
  config.token_lifetime = 1.hour

  # For Auth0
  config.token_audience = -> { Rails.application.secrets.auth0_client_id }
  config.token_secret_signature_key = -> { JWT.base64url_decode Rails.application.secrets.auth0_client_secret }
end

Authenticating from a web or mobile application

Example request to get a token from your API:

POST /user_token
{"auth": {"email": "[email protected]", "password": "secret"}}

Example response from the API:

201 Created
{"jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"}

To make an authenticated request to your API, you need to pass the token via the request header:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
GET /my_resources

Knock responds with a 404 Not Found when the user cannot be found or the password is invalid. This is a security best practice to avoid giving away information about the existence or not of a particular user.

NB: HTTPS should always be enabled when sending a password or token in your request.

Authenticated tests

To authenticate within your tests:

  1. Create a valid token
  2. Pass it in your request

e.g.

class SecuredResourcesControllerTest < ActionDispatch::IntegrationTest
  def authenticated_header
    token = Knock::AuthToken.new(payload: { sub: users(:one).id }).token

    {
      'Authorization': "Bearer #{token}"
    }
  end

  it 'responds successfully' do
    get secured_resources_url, headers: authenticated_header

    assert_response :success
  end
end

Without ActiveRecord

If no ActiveRecord is used, then you will need to specify what Exception will be used when the user is not found with the given credentials.

Knock.setup do |config|

  # Exception Class
  # ---------------
  #
  # Configure the Exception to be used (raised and rescued) for User Not Found.
  # note: change this if ActiveRecord is not being used.
  #
  # Default:
  config.not_found_exception_class_name = 'MyCustomException'
end

Algorithms

The JWT spec supports different kind of cryptographic signing algorithms. You can set token_signature_algorithm to use the one you want in the initializer or do nothing and use the default one (HS256).

You can specify any of the algorithms supported by the jwt gem.

If the algorithm you use requires a public key, you also need to set token_public_key in the initializer.

CORS

To enable cross-origin resource sharing, check out the rack-cors gem.

Related links

Contributing

  1. Fork it ( https://github.com/nsarno/knock/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

License

MIT

knock's People

Contributors

adonespitogo avatar albertobajo avatar aldesantis avatar anderslemke avatar artygus avatar bmcdaniel11 avatar duboff avatar esquith avatar eturino avatar gustavovnicius avatar kalashnikovisme avatar lassebunk avatar nicktomlin avatar nsarno avatar oreshinya avatar ristovskiv avatar sachse avatar tappleby avatar toby-1-kenobi avatar wkurosawa avatar zudochkin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

knock's Issues

Document change in header-passed token representation in CHANGELOG

Commit 18b2cfb now requires prefixing a header-passed token with a Bearer string. The previous release supported both forms, with and without the prefix. This breaks compatibility with all users who did not use prefixed tokens.

Please document this change in the CHANGELOG and / or consider changing the regular expression to accommodate the old behaviour.

Support for Rails 4.0.x ?

When I run bundle update I get:
In Gemfile:
rails (= 4.0.13)
knock was resolved to 1.0.0, which depends on
rails (~> 4.2)
I tried to force a lower version of knock, but this was "not found."

Going to the next version of Rails has many code-breaking changes within this app.
Is there a way to run knock on Rails 4.0.x ?

Verifying that authenticate is called.

It would be nice if there was built in support for verifying that authentication is enforced to lock down an application much like verify_authorized in Pundit.

Comments? Is this something you would like to see in a PR?

I'm thinking of something like:

module Knock::Authenticable
  def current_user
    @current_user ||= begin
      token = params[:token] || request.headers['Authorization'].split.last
      Knock::AuthToken.new(token: token).current_user
    rescue
      nil
    end
  end

  def authenticate
    @_authentication_performed = true
    head :unauthorized unless current_user
  end

  def authentication_performed?
    !!@_authentication_performed
  end

  def verify_authentication
    raise Knock::AuthenticationNotPerformedError unless authentication_performed?
  end
end

Usage:

class ApplicationController < ActionController::API
  include Knock::Authenticable 
  after_action :verify_authentication, except: [:show, :index]
end

404 on login response format

by defualt knock returns 'json' in response format heade. I would like to return "application/vnd.api+json

I tried to costumiz eit with an after_action:

response.content_type = "application/vnd.api+json"

but it doesn't work.

I creaed y own contrller for this, but will be great to add it as an option.

Thanks!

Allow passing auth_params as a whole to authenticate (v2)

This would give the implementer the freedom to implement authenticate how they choose. I may want to pass additional information to authenticate or provide a password-less authentication mechanism.

Granted, it looks like you're trying to adhere to the interface that has_secure_password provides, but there are many use cases where this doesn't work. So making it a configurable option might make sense.

initializer broken by ruby-jwt api changes

I found config.token_secret_signature_key was broken by ruby-jwt API updates ...

# config.token_secret_signature_key = -> { JWT.base64url_decode Rails.application.secrets.auth0_client_secret }

Latest ruby-jwt(v1.5.3) completely removes base64url_decode method from JWT module(at this PR)

BTW, We may use these work around as a temporary solution :)
(we may have better solution for this problem...)

require 'base64'

# extracted from original [method](http://www.rubydoc.info/github/jwt/ruby-jwt/JWT.base64url_decode)
config.token_secret_signature_key = -> {
    secret = Rails.application.secrets.auth0_client_secret
    secret += '=' * (4 - secret.length.modulo(4))
    Base64.decode64(secret.tr('-_', '+/'))
  }

Passing token from iOS app returns 401

After several days of debugging and even nuking my repo and starting over, I still can't seem to get any authorization with a JWT token I'm passing from an iOS app authenticated with Auth0 Lock. After updating to Knock 1.5, I've narrowed it down to self.from_token_payload not creating a new user. Any assistance would be greatly appreciated!
Here's my repo: https://github.com/brandonmanson/happening-api

Adding custom message when RecordNotFound exceptions occurs

Hey, I see you specify for us to raise an ActiveRecord::RecordNotFound for the authentication process but I am having trouble doing so as I do not know where to do it since the controller for generating tokens based on user credentials is the one you provide with your gem.

What I would like to do is send back with the status a response with a custom message like "Wrong Credentials" for example when such exception occurs. I imagine I should use a rescue but I do not know how or where, thanks.

uninitialized constant Knock

I changed my development machine. The same code that works fine on the old machine, now on the new machine gives this error:

uninitialized constant Knock

from this line in routes.rb
mount Knock::Engine => '/knock'

When I comment out that line I get

uninitialized constant ApplicationController::Knock

from this line in application_controller.rb
include Knock::Authenticable

The only difference I can think of from old machine to new is that this time I used rbenv instead of RVM, and also my ruby version is 2.3.0 instead of 2.2.3

Revoking a token

I need to know how to handle the logout operation, because the token will be valid up to the time mentioned in the expiry claim, but if a user log out from the application before the expiry time, the token should become invalid.
I was searching the way to revoke a jwt, i found some of the solutions here where someone said to use blacklisting mechanism and use of refresh token, i need to know whether these features are implemented in the knock or any other alternatives for invalidating a JWT.

URL authentication

Would be nice be able to pass the token via query string. Something like

token = request.headers['Authorization'].split(' ').last || params[:token]

Interested?

Readme inconsistent with 1.4.0?

I updated to 1.4.0 and everything stopped working. I assume there are some changes I need to make but on the readme the setup is exactly the same. Any chance for explaining what has changed?

Typo in generators

lib/generators/templates/knock.rb:51

Believe you mean identify but wrote indentify

`current_user` name collision

Using Knock I added token-based authentication to a rails app that already had session-based authentication. There was already a current_user method that was included in ApplicationController which looked in the session for the logged in user. This method prevented Knock authentication working because Knock checks if it can get a result from current_user to see if the user is authenticated, but it would call my current_user method instead of it's own.

To work around this I had to change the name of my current_user method to something else.

This sort of collision should be prevented using namespaces or something like that. At the very least it should be clearly documented that you can't have your own current_user method in controllers using Knock. It would have saved me a lot of debugging time.

Update documentation for testing with Rails 5

Rails 5 has now been released and ActionController::TestCase is deprecated so the documentation on testing is outdated. As far as I can tell the request.env object is no longer accessible. Instead, what I've been doing is something like this:

test_helper.rb

def authentication_token
  Knock::AuthToken.new(payload: { sub: users(:one).id }).token
end

def authenticated_headers
  {
    'Authorization': "Bearer #{authentication_token}"
  }
end

controller_test.rb

test "should respond successfully" do
    get model_url(@model), headers: authenticated_headers
end

Maybe there's a better way to do this? Once a format has been decided on I can make a pull request, if you'd like.

Unable to autoload constant Engine

Getting the following error (I followed the Auth0 manual)

LoadError (Unable to autoload constant Engine, expected /Users/mikhaildubov/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/knock-1.3.0/lib/knock/engine.rb to define it):

Any idea why this is happening? Appreciate any pointers.

Authorization header works with any random JWT prefix

Awesome gem.

I followed Adam's JWT tutorial in the past: http://adamalbrecht.com/2015/07/20/authentication-using-json-web-tokens-using-rails-and-react/ which builds a JWT from scratch without using gems.

Today, I tried this library, works like a gem (pun intended).

I have one issue though, hopefully it hasn't been asked before.

When I use cURL or Postman to make the request:

screen shot 2016-05-22 at 5 34 00 pm

It doesn't matter whether I put in the HTTP Headers:

"Authorization: JWT <the_real_JWT_here>"

Or

"Authorization: Blah <the_real_JWT_here>"

The Rails server still lets it through....is this how it's suppose to work?

For example, this Github README uses Bearer <JWT_token>. I would have thought a real JWT should enforce the Authorization header to have the word "JWT" instead of letting anything there.

Any ideas?

Overlap with Warden

Hi,

I've noticed that this gem does not have warden as a dependency. I presume this is intentional? Is this gem reimplementing part of warden functionality?

I'm wondering what would it take to integrate knock as an authentication strategy into warden

Rails cannot recognise the engine version

Versions of rails and rails-api:

gem 'rails-api', '0.4.0'
gem 'rails', '~> 4.2.3'

Specs written with rspec get in some kind of conflict and throws the error that it cannot find the version of the engine version.
The path provided in the error is the same as the version file but somehow it cannot be loaded.

[Question] How do I authenticate an Auth0 user in my request specs?

I'm trying to write some request specs for my API but the following code results in a 401 status:

# spec/support/auth0.rb

def authenticate(user)
  # user.auth0_id contains the actual user id from Auth0
  Knock::AuthToken.new(payload: { sub: user.auth0_id }).token
end
# spec/requests/dashboard_spec.rb

require "rails_helper"

RSpec.describe 'GET /dashboard' do
  let(:user) { create(:user) }
  let(:auth_token) { authenticate(user) }

  context 'when a user is logged in' do
    it "returns a 200 response" do
      get '/dashboard', headers: { 'Authorization' => "Bearer #{auth_token}" }
      expect(response.status).to eq 200
    end
  end
end

Any idea on how to resolve this? By the way, i'm using the v2 branch with my updates found here

404 response when credentials are bad

When a client tries to authenticate with bad credentials the server response is 404. The client then wont know if the credentials are bad or the sever is offline. Perhaps a 401 or 403 response would be better.

Time of token expiration?

Hi, how long the token is valid?
Is there a way to configure this time?

Thanks!!

Congratulations for the job with this gem!!!

Unauthorized response in specs

When testing the response is always unauthorized with response.body equaling f.

deliveries_controller_spec.rb

require 'rails_helper'

module V1
  RSpec.describe DeliveriesController, type: :controller do
    let(:auth_token) { authenticate }
    context 'index' do
      before do
        @deliveries = [DateTime.now, (DateTime.now - 1), DateTime.now, (DateTime.now + 1), DateTime.now].each_with_object([]) do |time, stash|
          stash << create(:delivery, eta: time)
        end

        @deliveries.each_with_index do |delivery, index|
          delivery.locations << create(:location, name: "Location #{index}")
        end
      end
      it 'give all deliveries that have an eta for the current day' do
        get :index, headers: { 'Authorization' => "Bearer #{auth_token}" }
        expected_count = 3
        full_count = @deliveries.size
        expect(json_data.size).to_not be(full_count)
        expect(json_data.size).to be(expected_count)
      end
      context 'by location' do
        it 'give all deliveries for a location for that day' do
          location = @deliveries.last.locations.first
          get :index, location_id: location.id, headers: { 'Authorization' => "Bearer #{auth_token}" }
          expected_count = 1
          full_count = @deliveries.size
          puts response.body
          expect(json_data.size).to_not be(full_count)
          expect(json_data.size).to be(expected_count)
        end
      end
    end
    context 'CRUD' do
      it 'show' do
        delivery = create(:delivery)
        get :show, id: delivery, headers: { 'Authorization' => "Bearer #{auth_token}" }
        expect(response).to be_successful
        expect(json_data).to include(:id, :type, :attributes)
      end
      it 'create' do
        post :create, json_api_format { attributes_for(:delivery) }
        expect(response).to be_successful
        expect(json_data).to include(:id, :type, :attributes)
      end

      it 'update' do
        delivery = create(:delivery)
        old_cargo = delivery.cargo
        expected_cargo = 'Updated Cargo'
        delivery.cargo = expected_cargo
        patch :update, json_api_format(delivery.id) { delivery.attributes }, headers: { 'Authorization' => "Bearer #{auth_token}" }
        delivery.reload
        expect(delivery.cargo).to_not eq(old_cargo)
        expect(delivery.cargo).to eq(expected_cargo)
      end
    end
  end
end

deliveries_controller.rb

module V1
  class DeliveriesController < ApplicationController
    before_action :authenticate
    def index
      if location
        render json: location.deliveries.today, status: :ok
      else
        render json: Delivery.today, include: '*', status: :ok
      end
    end

    def show
      delivery = Delivery.find delivery_id
      render json: delivery, include: '*', status: :ok
    end

    def create
      delivery = Delivery.create delivery_params
      render json: delivery, include: '*', status: :created
    end

    def update
      delivery = Delivery.find delivery_id
      delivery.update delivery_params
      render json: delivery, status: :ok
    end

    private

    def location
      @location ||= Location.find_by(id: location_params[:location_id])
    end

    def location_params
      params.permit(:location_id)
    end

    def delivery_id
      params[:id]
    end

    def delivery_params
      ActiveModelSerializers::Deserialization
        .jsonapi_parse(params, only: [:cargo, :cargo_quantity, :notes, :arrive_at, :escort,
                                      :priority, :processing_time, :eta, :icon_url, :escort_badge_number])
    end
  end
end

spec support

def authenticate
   token = Knock::AuthToken.new(payload: { sub: create(:driver).id }).token
   request.env['HTTP_AUTHORIZATION'] = "Bearer #{token}"
 end

config/initializers/knock.rb

  config.current_user_from_handle = -> (handle) { Driver.find_by! Knock.handle_attr => handle }

  config.current_user_from_token = -> (claims) { Driver.find claims['sub'] }

Add an action to check if token is valid

I think it would be nice to have an additional action alongside AuthToken#create (maybe AuthToken#validate) that simply returns success if the provided token is valid.

It can be useful when the client just wants to check if the token is valid and hasn't expired without having to decode it.

Adding private claims to the token

Hi there, just wondering if you thoughts on adding additional claims to the token payload. I'd like to add some additional user information to it but it looks like I'd have to subclass the AuthTokenController (which will be easier once #47 is fixed).

Thanks and cheers

How to skip authenticate! some specific actions?

Hello I'm trying skip athenticate method this way:

skip_before_filter :authenticate, only: :half_hourly
and
skip_before_filter :authenticate!, only: :half_hourly

but this is not working.

Can you help me?

No method error: User doesn't have 'authenticate'

Knock looks like a great solution but I'm having issues. I know Knock is in there. The routes are registered and when I hit a secured page with no headers supplied, I get a 401. However, when I do supply the correct headers, I get this no method error. Any ideas what's up?

https://github.com/brandonpittman/knock_test/blob/master/app/controllers/users_controller.rb

Has anyone done a tutorial using Knock that you know of? I'm not having a lot of luck getting it up and running.

Multi-tenant solution

I'm looking at providing an API that will have multiple token_audience/token_secret_signature_key values depending on the particular account that a user is associated with. Right now, it looks like the only way I could deal with this scenario is to set those config values manually for each request. However, I'm concerned that if I'm changing things at a global module level, I might run into an issue where multiple app requests running in parallel are overwriting the config values and stomping on each other (maybe only if I have a multi-threaded app server?). If I could, I would be happy to pass those values directly to the Knock::AuthToken model, but that's not how it works currently.

Anyway, just curious if you have an idea of how to go about this. Thanks!

Syntax error during 'rails generate knock:install'

Hi,

executing :rails generate knock:install on my dev environment (Jruby 1.7.10 on Windows 7)

I got:

SyntaxError: C:/Ruby/jruby-1.7.10/lib/ruby/gems/shared/gems/knock-1.3.0/lib/knock.rb:12: syntax error,
 unexpected tLPAREN_ARG self.current_user_from_token = -> (claims) { User.find claims['sub'] }

I'm opening a pull request for removing the spaces that cause problem.
Let me know if is useful.

Using Knock for SSO with multiple servers

I'm still wrapping my mind around how JWTs work and hoping for some guidance on how I might use Knock to help me in my situation.

I have an Authentication Server (Rails), a Client (Angular2), and a Data API (Rails). From the client I need to be able to authenticate with the auth server which would then give me permission to access the data api. I'm a little confused how to use the received JWT from the auth server with the data api. How does the data api decode the request that was signed by the auth server? Do I need to have the same 'secret' on both servers? I'm going for an SSO solution here so I'd like this to work with any *.mydomain.com. I assume Knock would be running on the Auth server since it has User accounts and I would need to implement something with straight JWT decoding on the Data API server.

I really appreciate any advice. Thanks!

Does this support automatic refresh tokens?

I'm new to JWT, but it looks better than just using the same API token forever.

I know the token expires after a day (by default), but does that mean the user will have to re-login again?

  • this could lead to some un-desired behavior if someone's token is about to expire when they are in the middle of work.

How does auth work between multiple devices? (esp in the case of a refresh token)

permanent tokens?

Is there a recommended method for generating permanent tokens?

I ask because I'm making both a mobile app and the Rails API it will use, and I only want the user to login once, after they install the app.

I noticed the default expiration period is config.token_lifetime = 1.day with no obvious way to set this to infinity/nil. And after a cursory search I didn't see any mention of refresh tokens.

For now I've set it to an arbitrary long-term future date, 10.years. And will store the token locally in the app, but is that a bad idea? Thanks

Setting @current_user in authenticable.rb

In authenticable.rb the @current_user is retrieved like this

@current_user = User.find(payload['user_id'])

but since there is no User model in the lib it will force whoever who uses knock to have a model named User and expect a claim named user_id to be present in the JWT.
What I'd like to have is a way to define how the user is retrieved from my DB, e.g. in my app's config/knock.rb I could have:

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

and then in authenticable.rb

@current_user = Knock.current_user_from_token.call(payload)

This will allow to fetch the user from any model using any claim in the JWT

Namespacing models

Hi there.

I'm trying to implement Knock in a Rails 5 API, where I have everything namespaced (e.g. V1::User, V1::UsersController, etc..).

When mounting the knock authentication endpoint inside the namespace, like this, it works fine for exchanging username and password for a JWT:

  constraints format: :json, defaults: { format: :json } do
    namespace :v1 do
      post :user_token, to: 'user_token#create'
      resources :rooms
    end
  end

It doesn't work to go to the rooms endpoint afterwords, using the new JWT token. I get this exception: NameError: uninitialized constant User. This is because I have this in my V1::BaseController:

before_action :authenticate_user

Here this is being constantized into the User model, so it's clear that a namespace is missing.

I then tried adding this to my controller instead:

before_action :authenticate_v1_user

But this gets transformed into a V1User class, not as expected a V1::User.

Is there a way that I'm not seeing for easily letting Knock know that I'm trying to get at a namespaced user?

Thanks in advance,
Emil

Devise Integration Example

Anyone try integrating this with Devise yet? I want Devise for it's user and password management, but need JWT since I have an API.

Knock::AuthTokenController extending

Hello. In some cases AuthTokenController may need custom behaviour, but all the methods inside except create action are private. What about making them protected? This will allow users add some custom logic. For example, adding expiration date or user identifier to response and etc

Support for Rails 5 RCs

Any recommendation on using Knock with the Rails 5 release candidates? Right now, the dependency is based on official releases (per PR #30). In the meantime, I've forked this repo and adjusted the dependency accordingly but wanted to know if you're planning an official release of Knock that supports the release candidates or not.

Authentication for a scoped user?

I would like to use Knock for an API that allows the reuse of an email address against multiple different accounts. Just like Slack, the account would be determined by the subdomain that the user logs in from.

Is it possible to scope the current_user to be found via an associated Account object?

e.g. Users.where(account_id: $account_id).find_by! Knock.handle_attr => handle

undefined method `length' for nil:NilClass while running specs

Hello,
I try to authenticate user in my tests. So far my spec looks like:

require 'rails_helper'

RSpec.describe 'GET /posts' do
  subject { response }

  let(:user) { create(:user) }

  it 'authenticate user' do
    authenticate
    get '/posts'
    expect(response.status).to eq 200
  end
end

My User model has auth_id column which stores auth0 user id. My code method is below.

def authenticate
  token = Knock::AuthToken.new(payload: { sub: user.auth_id }).token
  request.env['HTTP_AUTHORIZATION'] = "Bearer #{token}"
end

Every time I run spec I receive error about undefined method length.

Failure/Error: authenticate
  NoMethodError:
    undefined method `length' for nil:NilClass

I will really appreciate it if someone can suggest me what's wrong with my code.

Thanks!

A [GET] on /users respond with 'NameError (uninitialized constant Knock)'

I use rails 5.0.0.beta3 and rbenv and used this guide
With rbenv i created a new rails api project rbenv exec rails _5.0.0.beta3_ new levented --api
After that i scaffold my user bin/rails g scaffold user name:string family_name:string nick_name:string email:string

routes.rb

Rails.application.routes.draw do
  mount Knock::Engine => '/knock'
  resources :users
end

application_controller.rb

class ApplicationController < ActionController::API
  include Knock::Authenticable
end

users_controller.rb

class UsersController < ApplicationController
  before_action :set_user, only: [:show, :update, :destroy]

  # GET /users
  def index
    @users = User.all

    render json: @users
  end
end

A [GET] to /users prints the following error

ActionController::RoutingError (uninitialized constant ApplicationController::Knock):

app/controllers/application_controller.rb:2:in `<class:ApplicationController>'
app/controllers/application_controller.rb:1:in `<top (required)>'
app/controllers/users_controller.rb:1:in `<top (required)>'
Started GET "/users" for 127.0.0.1 at 2016-03-15 20:57:53 +0100

What did i wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.