{"id":15151529,"url":"https://github.com/mayurifag/knock_knock","last_synced_at":"2025-09-29T20:31:34.183Z","repository":{"id":97296026,"uuid":"219995256","full_name":"Mayurifag/knock_knock","owner":"Mayurifag","description":"JWT Rails 6+ API authentication gem, re-implementation of Knock.","archived":true,"fork":false,"pushed_at":"2020-09-11T18:36:42.000Z","size":69,"stargazers_count":4,"open_issues_count":6,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-09-27T15:04:07.852Z","etag":null,"topics":["api","authentication","gem","jwt","jwt-auth","jwt-authentication","jwt-claims","knock","rails6","rubygems","travis-ci","zeitwerk"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mayurifag.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-06T12:47:26.000Z","updated_at":"2023-02-12T20:21:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"34568c05-aa89-4c28-8472-64b4d5c801bc","html_url":"https://github.com/Mayurifag/knock_knock","commit_stats":{"total_commits":14,"total_committers":1,"mean_commits":14.0,"dds":0.0,"last_synced_commit":"1fd1620f846c9eddc1ee0622b1c6f289c6d64593"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mayurifag%2Fknock_knock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mayurifag%2Fknock_knock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mayurifag%2Fknock_knock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mayurifag%2Fknock_knock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mayurifag","download_url":"https://codeload.github.com/Mayurifag/knock_knock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234659897,"owners_count":18867637,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","authentication","gem","jwt","jwt-auth","jwt-authentication","jwt-claims","knock","rails6","rubygems","travis-ci","zeitwerk"],"created_at":"2024-09-26T15:04:06.477Z","updated_at":"2025-09-29T20:31:28.814Z","avatar_url":"https://github.com/Mayurifag.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# knock_knock\n\n[![Gem Version](https://badge.fury.io/rb/knock_knock.svg)](http://badge.fury.io/rb/knock_knock)\n[![Build Status](https://travis-ci.com/Mayurifag/knock_knock.svg)](https://travis-ci.com/Mayurifag/knock_knock)\n\n\n## Description\n\n`knock_knock` is an authentication solution for Rails API-only application based\non JSON Web Tokens.\n\nThis gem is a re-implementation of `Knock` gem to work with Rails 6 (and\nzeitwerk) with some major and minor changes, i.e. 422 on wrong password instead\nof 404.\n\nI'm trying so stay with asame interface on this gem.\n\n## Why should I use this?\n\n- It's lightweight.\n- It's tailored for Rails API-only application.\n- It's [stateless](https://en.wikipedia.org/wiki/Representational_state_transfer#Stateless).\n- It works out of the box with [Auth0](https://auth0.com/docs/server-apis/rails).\n\n## Getting Started\n\n### Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'knock_knock'\n```\n\nThen execute:\n\n    $ bundle install\n\nFinally, run the install generator:\n\n    $ rails generate knock_knock:install\n\nIt will create the following initializer `config/initializers/knock_knock.rb`.\nThis file contains all of the existing configuration options.\n\nIf you don't use an external authentication solution like Auth0, you also need\nto provide a way for users to sign in:\n\n    $ rails generate knock_knock:token_controller user\n\nThis will generate the controller `user_token_controller.rb` and add the\nrequired route to your `config/routes.rb` file.\n\nYou can also provide another entity instead of `user`. E.g. `admin`\n\n### Requirements\n\n`knock_knock` makes one assumption about your user model:\n\nIt must have an `authenticate` method, similar to the one added by [has_secure_password](http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password).\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  has_secure_password\nend\n```\n\nUsing `has_secure_password` is recommended, but you don't have to as long as\nyour user model implements an `authenticate` instance method with the same\nbehavior.\n\n### Usage\n\nInclude the `KnockKnock::Authenticable` module in your `ApplicationController`\n\n```ruby\nclass ApplicationController \u003c ActionController::API\n  include KnockKnock::Authenticable\nend\n```\n\nYou can now protect your resources by calling `authenticate_user` as a before_action\ninside your controllers:\n\n```ruby\nclass SecuredController \u003c ApplicationController\n  before_action :authenticate_user\n\n  def index\n    # etc...\n  end\n\n  # etc...\nend\n```\n\nYou can access the current user in your controller with `current_user`.\n\nIf no valid token is passed with the request, KnockKnock will respond with:\n\n```\nhead :unauthorized\n```\n\nYou can modify this behaviour by overriding `unauthorized_entity` in your controller.\n\nYou also have access directly to `current_user` which will try to authenticate\nor return `nil`:\n\n```ruby\ndef index\n  if current_user\n    # do something\n  else\n    # do something else\n  end\nend\n```\n\n_Note: the `authenticate_user` method uses the `current_user` method. Overwriting `current_user` may cause unexpected behaviour._\n\nYou can do the exact same thing for any entity. E.g. for `Admin`, use `authenticate_admin` and `current_admin` instead.\n\nIf you're using a namespaced model, KnockKnock won't be able to infer it\nautomatically from the method name. Instead you can use `authenticate_for`\ndirectly like this:\n\n```ruby\nclass ApplicationController \u003c ActionController::Base\n  include KnockKnock::Authenticable\n\n  private\n\n  def authenticate_v1_user\n    authenticate_for V1::User\n  end\nend\n```\n\n```ruby\nclass SecuredController \u003c ApplicationController\n  before_action :authenticate_v1_user\nend\n```\n\nThen you get the current user by calling `current_v1_user` instead of `current_user`.\n\n### Customization\n\n#### Via the entity model\n\nThe entity model (e.g. `User`) can implement specific methods to provide\ncustomization over different parts of the authentication process.\n\n- **Find the entity when creating the token (when signing in)**\n\nBy default, KnockKnock tries to find the entity by email. If you want to modify this\nbehaviour, implement within your entity model a class method `from_token_request`\nthat takes the request in argument.\n\nE.g.\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  def self.from_token_request request\n    # Returns a valid user, `nil` or raise `KnockKnock.not_found_exception_class_name`\n    # e.g.\n    #   email = request.params[\"email\"]\n    #   self.find_by email: email\n  end\nend\n```\n\n- **Find the authenticated entity from the token payload (when authenticating a request)**\n\nBy default, KnockKnock assumes the payload as a subject (`sub`) claim containing the entity's id\nand calls `find` on the model. If you want to modify this behaviour, implement within\nyour entity model a class method `from_token_payload` that takes the\npayload in argument.\n\nE.g.\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  def self.from_token_payload payload\n    # Returns a valid user, `nil` or raise\n    # e.g.\n    #   self.find payload[\"sub\"]\n  end\nend\n```\n\n- **Modify the token payload**\n\nBy default the token payload contains the entity's id inside the subject (`sub`) claim.\nIf you want to modify this behaviour, implement within your entity model an instance method\n`to_token_payload` that returns a hash representing the payload.\n\nE.g.\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  def to_token_payload\n    # Returns the payload as a hash\n  end\nend\n```\n\n#### Via the initializer\n\nThe initializer [config/initializers/knock_knock.rb](https://github.com/Mayurifag/knock_knock/blob/master/lib/generators/knock_knock/templates/knock_knock.rb)\nis generated when `rails g knock_knock:install` is executed. Each configuration\nvariable is documented with comments in the initializer itself.\n\n### Authenticating from a web or mobile application\n\nExample request to get a token from your API:\n```\nPOST /user_token\n{\"auth\": {\"email\": \"foo@bar.com\", \"password\": \"secret\"}}\n```\n\nExample response from the API:\n```\n201 Created\n{\"jwt\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\"}\n```\n\nTo make an authenticated request to your API, you need to pass the token via the\nrequest header:\n```\nAuthorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\nGET /my_resources\n```\n\nKnockKnock responds with a `422 Unauthorized` when the user cannot be found or\nthe password is invalid. This is a security best practice to avoid giving away\ninformation about the existence or not of a particular user.\n\n**NB:** HTTPS should always be enabled when sending a password or token in your\nrequest.\n\n### Authenticated tests\n\nTo authenticate within your tests:\n\n1. Create a valid token\n2. Pass it in your request\n\ne.g.\n\n```ruby\nclass SecuredResourcesControllerTest \u003c ActionDispatch::IntegrationTest\n  def authenticated_header\n    token = KnockKnock::AuthToken.new(payload: { sub: users(:one).id }).token\n\n    {\n      'Authorization': \"Bearer #{token}\"\n    }\n  end\n\n  it 'responds successfully' do\n    get secured_resources_url, headers: authenticated_header\n\n    assert_response :success\n  end\nend\n```\n\n#### Without ActiveRecord\n\nIf no ActiveRecord is used, then you will need to specify what Exception will be\nused when the user is not found with the given credentials.\n\n```ruby\nKnockKnock.setup do |config|\n\n  # Exception Class\n  # ---------------\n  #\n  # Configure the Exception to be used (raised and rescued) for User Not Found.\n  # note: change this if ActiveRecord is not being used.\n  #\n  # Default:\n  config.not_found_exception_class_name = 'MyCustomException'\nend\n```\n\n### Algorithms\n\nThe JWT spec supports different kind of cryptographic signing algorithms.\nYou can set `token_signature_algorithm` to use the one you want in the\ninitializer or do nothing and use the default one (HS256).\n\nYou can specify any of the algorithms supported by the\n[jwt](https://github.com/jwt/ruby-jwt) gem.\n\nIf the algorithm you use requires a public key, you also need to set\n`token_public_key` in the initializer.\n\n## Migrate from Knock\n\nTo migrate from `knock` you just need replace all things in your code from `knock`\nto `knock_knock` and from `Knock` to `KnockKnock`.\n\nYou may look at [this commit](https://github.com/Mayurifag/bets_accounting/commit/8da1f3897457d497612c542f25531d9abc891397)\nfor a reference.\n\n## CORS\n\nTo enable cross-origin resource sharing, check out the [rack-cors](https://github.com/cyu/rack-cors) gem.\n\n## Related links\n\n- [10 things you should know about tokens](https://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/)\n\n\n## License\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## TODO:\n\n[] Readme and gemspec summaries etc +badges +ci beautify\n[] changelog\n[] COC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmayurifag%2Fknock_knock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmayurifag%2Fknock_knock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmayurifag%2Fknock_knock/lists"}