Seamless JWT authentication for Rails API
Knock is an authentication solution for Rails API-only application based on JSON Web Tokens.
- It's lightweight.
- It's tailored for Rails API-only application.
- It's stateless.
- It works out of the box with Auth0.
Yes.
- Easy way to authenticate multiple user types (User, Admin, ...)
- Remove ActiveRecord dependency
Really want some feature? Don't hesitate to open an issue :)
Add this line to your application's Gemfile:
gem 'knock'
And then execute:
$ bundle install
Finally, run the install generator:
$ rails generate knock:install
It will create the following initializer config/initializers/knock.rb
.
This file contains all the informations about the existing configuration options.
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.
Mount the Knock::Engine
in your config/routes.rb
Rails.application.routes.draw do
mount Knock::Engine => "/knock"
# your routes ...
end
Then include the Knock::Authenticable
module in your ApplicationController
class ApplicationController < ActionController::API
include Knock::Authenticable
end
You can now protect your resources by adding the authenticate
before_action
to your controllers like this:
class MyResourcesController < ApplicationController
before_action :authenticate
def index
# etc...
end
# etc...
end
If no valid token is passed with the request, Knock will respond with:
head :unauthorized
If you just want to read the current_user
, without actually authenticating, you can also do that:
class CurrentUsersController < ApplicationController
def show
if current_user
head :ok
else
head :not_found
end
end
end
Note that the authenticate
method depends upon the current_user
method. Overwriting current_user
in the controller may break the authenticate
method.
Example request to get a token from your API:
POST /knock/auth_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 in the request header:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
GET /my_resources
NB: HTTPS should always be enabled when sending a password or token in your request.
To authenticate within your tests:
- Create a valid token
- Pass it in your request
e.g.
class MyResourcesControllerTest < ActionController::TestCase
def authenticate
token = Knock::AuthToken.new(payload: { sub: users(:one).id }).token
request.env['HTTP_AUTHORIZATION'] = "Bearer #{token}"
end
setup do
authenticate
end
it 'responds successfully' do
get :index
assert_response :success
end
end
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
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.
To enable cross-origin resource sharing, check out the rack-cors gem.
- Fork it ( https://github.com/nsarno/knock/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
MIT