knocknock
Seamless JWT authentication for Rails API
Description
Knock is an authentication solution for Rails API-only application based on JSON Web Tokens.
What are JSON Web Tokens?
Why should I use this?
- It's lightweight.
- It's tailored for Rails API-only application.
- It's stateless.
- It works out of the box with Auth0.
Is this gem going to be maintained?
Yes. And we will keep improving it.
Getting Started
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.
Knock (>= 2.0) can handle multiple user models (eg: User, Admin, etc).
Although, for the sake of simplicity, all examples in this README will use the User model.
Installation
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.
If you don't use an external authentication solution like Auth0, you also need to provide a way for users to authenticate:
$ rails generate knock:token_controller user
This will generate the controller user_token_controller.rb and add the required
route to your config/routes.rb file.
Usage
Include the Knock::Authenticatable module in your ApplicationController
class ApplicationController < ActionController::API
include Knock::Authenticatable
end
You can now restrict access to your controllers like this:
class SecuredController < ApplicationController
before_action :authenticate_user
def index
# etc...
end
# etc...
end
If your user model is something other than User, replace "user" with "yourmodel". The same logic applies everywhere.
You can access the current authenticated user in your controller with this method:
current_user
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
Authenticating from a web or mobile application:
Example request to get a token from your API:
POST /user_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.
Authenticated tests
To authenticate within your tests:
- Create a valid token
- Pass it in your request
e.g.
class SecuredControllerTest < 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
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
- 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
License
MIT