Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
This repository was archived by the owner on Dec 25, 2020. It is now read-only.
/knock_knockPublic archive

JWT Rails 6+ API authentication gem, re-implementation of Knock.

License

NotificationsYou must be signed in to change notification settings

Mayurifag/knock_knock

Repository files navigation

Gem VersionBuild Status

Description

knock_knock is an authentication solution for Rails API-only application basedon JSON Web Tokens.

This gem is a re-implementation ofKnock gem to work with Rails 6 (andzeitwerk) with some major and minor changes, i.e. 422 on wrong password insteadof 404.

I'm trying so stay with asame interface on this gem.

Why should I use this?

  • It's lightweight.
  • It's tailored for Rails API-only application.
  • It'sstateless.
  • It works out of the box withAuth0.

Getting Started

Installation

Add this line to your application's Gemfile:

gem'knock_knock'

Then execute:

$ bundle install

Finally, run the install generator:

$ rails generate knock_knock:install

It will create the following initializerconfig/initializers/knock_knock.rb.This file contains all of the existing configuration options.

If you don't use an external authentication solution like Auth0, you also needto provide a way for users to sign in:

$ rails generate knock_knock:token_controller user

This will generate the controlleruser_token_controller.rb and add therequired route to yourconfig/routes.rb file.

You can also provide another entity instead ofuser. E.g.admin

Requirements

knock_knock makes one assumption about your user model:

It must have anauthenticate method, similar to the one added byhas_secure_password.

classUser <ActiveRecord::Basehas_secure_passwordend

Usinghas_secure_password is recommended, but you don't have to as long asyour user model implements anauthenticate instance method with the samebehavior.

Usage

Include theKnockKnock::Authenticable module in yourApplicationController

classApplicationController <ActionController::APIincludeKnockKnock::Authenticableend

You can now protect your resources by callingauthenticate_user as a before_actioninside your controllers:

classSecuredController <ApplicationControllerbefore_action:authenticate_userdefindex# etc...end# etc...end

You can access the current user in your controller withcurrent_user.

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

head :unauthorized

You can modify this behaviour by overridingunauthorized_entity in your controller.

You also have access directly tocurrent_user which will try to authenticateor returnnil:

defindexifcurrent_user# do somethingelse# do something elseendend

Note: theauthenticate_user method uses thecurrent_user method. Overwritingcurrent_user may cause unexpected behaviour.

You can do the exact same thing for any entity. E.g. forAdmin, useauthenticate_admin andcurrent_admin instead.

If you're using a namespaced model, KnockKnock won't be able to infer itautomatically from the method name. Instead you can useauthenticate_fordirectly like this:

classApplicationController <ActionController::BaseincludeKnockKnock::Authenticableprivatedefauthenticate_v1_userauthenticate_forV1::Userendend
classSecuredController <ApplicationControllerbefore_action:authenticate_v1_userend

Then you get the current user by callingcurrent_v1_user instead ofcurrent_user.

Customization

Via the entity model

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

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

By default, KnockKnock tries to find the entity by email. If you want to modify thisbehaviour, implement within your entity model a class methodfrom_token_requestthat takes the request in argument.

E.g.

classUser <ActiveRecord::Basedefself.from_token_requestrequest# Returns a valid user, `nil` or raise `KnockKnock.not_found_exception_class_name`# e.g.#   email = request.params["email"]#   self.find_by email: emailendend
  • Find the authenticated entity from the token payload (when authenticating a request)

By default, KnockKnock assumes the payload as a subject (sub) claim containing the entity's idand callsfind on the model. If you want to modify this behaviour, implement withinyour entity model a class methodfrom_token_payload that takes thepayload in argument.

E.g.

classUser <ActiveRecord::Basedefself.from_token_payloadpayload# Returns a valid user, `nil` or raise# e.g.#   self.find payload["sub"]endend
  • 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 methodto_token_payload that returns a hash representing the payload.

E.g.

classUser <ActiveRecord::Basedefto_token_payload# Returns the payload as a hashendend

Via the initializer

The initializerconfig/initializers/knock_knock.rbis generated whenrails g knock_knock:install is executed. Each configurationvariable is documented with comments in the initializer itself.

Authenticating from a web or mobile application

Example request to get a token from your API:

POST /user_token{"auth": {"email": "foo@bar.com", "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 therequest header:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9GET /my_resources

KnockKnock responds with a422 Unauthorized when the user cannot be found orthe password is invalid. This is a security best practice to avoid giving awayinformation about the existence or not of a particular user.

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

Authenticated tests

To authenticate within your tests:

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

e.g.

classSecuredResourcesControllerTest <ActionDispatch::IntegrationTestdefauthenticated_headertoken=KnockKnock::AuthToken.new(payload:{sub:users(:one).id}).token{'Authorization':"Bearer#{token}"}endit'responds successfully'dogetsecured_resources_url,headers:authenticated_headerassert_response:successendend

Without ActiveRecord

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

KnockKnock.setupdo |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 settoken_signature_algorithm to use the one you want in theinitializer or do nothing and use the default one (HS256).

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

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

Migrate from Knock

To migrate fromknock you just need replace all things in your code fromknocktoknock_knock and fromKnock toKnockKnock.

You may look atthis commitfor a reference.

CORS

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

Related links

License

The gem is available as open source under the terms of theMIT License.

TODO:

[] Readme and gemspec summaries etc +badges +ci beautify[] changelog[] COC


[8]ページ先頭

©2009-2025 Movatter.jp