{"id":13416396,"url":"https://github.com/nsarno/knock","last_synced_at":"2025-03-14T23:31:47.234Z","repository":{"id":34943112,"uuid":"39015905","full_name":"nsarno/knock","owner":"nsarno","description":"Seamless JWT authentication for Rails API","archived":true,"fork":false,"pushed_at":"2021-03-21T22:06:07.000Z","size":174,"stargazers_count":2072,"open_issues_count":61,"forks_count":254,"subscribers_count":45,"default_branch":"master","last_synced_at":"2024-05-15T22:52:19.037Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"stripe/stripe-android","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nsarno.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-13T14:08:32.000Z","updated_at":"2024-05-06T12:40:02.000Z","dependencies_parsed_at":"2022-07-08T13:18:18.435Z","dependency_job_id":null,"html_url":"https://github.com/nsarno/knock","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarno%2Fknock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarno%2Fknock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarno%2Fknock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsarno%2Fknock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nsarno","download_url":"https://codeload.github.com/nsarno/knock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243663516,"owners_count":20327300,"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":[],"created_at":"2024-07-30T21:00:58.205Z","updated_at":"2025-03-14T23:31:42.219Z","avatar_url":"https://github.com/nsarno.png","language":"Ruby","readme":"## DISCLAIMER\n\nThis project is not being maintained and I don't recommend using it in its current form.\nAs an alternative, I recommend using the [jwt](https://github.com/jwt/ruby-jwt) gem directly.\n\n# knock\n\n[![Gem Version](https://badge.fury.io/rb/knock.svg)](http://badge.fury.io/rb/knock)\n[![Build Status](https://travis-ci.org/nsarno/knock.svg)](https://travis-ci.org/nsarno/knock)\n[![Code Climate](https://codeclimate.com/github/nsarno/knock/badges/gpa.svg)](https://codeclimate.com/github/nsarno/knock)\n\nSeamless JWT authentication for Rails API\n\n## Description\n\nKnock is an authentication solution for Rails API-only application based on JSON Web Tokens.\n\n## Getting Started\n\n### Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'knock'\n```\n\nThen execute:\n\n    $ bundle install\n\n### Requirements\n\nKnock 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 your user model implements an `authenticate` instance method with the same behavior.\n\n### Usage\n\nInclude the `Knock::Authenticable` module in your `ApplicationController`\n\n```ruby\nclass ApplicationController \u003c ActionController::API\n  include Knock::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, Knock 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 or 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, Knock won't be able to infer it automatically from the method name. Instead you can use `authenticate_for` directly like this:\n\n```ruby\nclass ApplicationController \u003c ActionController::Base\n  include Knock::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### Configuration\n\n#### In 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, Knock 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 `Knock.not_found_exception_class_name`\n    # e.g.\n    #   email = request.params[\"auth\"] \u0026\u0026 request.params[\"auth\"][\"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, Knock 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- **Token Lifetime**\n\nBy default the generated tokens will be valid, after generated, for 1 day.\nYou can change it in the Knock configuration file (config/knock.rb),\nsetting the desired lifetime:\n\nE.g.\n\n```ruby\n  Knock.token_lifetime = 3.hours\n```\n\nIf you are generating tokens for more than one entity, you can pass\neach lifetime in a hash, using the entities class names as keys, like:\n\nE.g.\n\n```ruby\n  # How long before a token is expired. If nil is provided,\n  # token will last forever.\n  Knock.token_lifetime = {\n    user: 1.day\n    admin: 30.minutes\n  }\n```\n\n#### In the initializer\n\nRead [lib/knock.rb](https://github.com/nsarno/knock/blob/master/lib/knock.rb) to learn about all the possible configuration options and their default values.\n\nYou can create an initializer like in the example below:\n\nInside `config/initializers/knock.rb`\n\n```ruby\nKnock.setup do |config|\n  config.token_lifetime = 1.hour\n\n  # For Auth0\n  config.token_audience = -\u003e { Rails.application.secrets.auth0_client_id }\n  config.token_secret_signature_key = -\u003e { JWT.base64url_decode Rails.application.secrets.auth0_client_secret }\nend\n```\n\n### Authenticating from a web or mobile application\n\nExample request to get a token from your API:\n\n```\nPOST /user_token\n{\"auth\": {\"email\": \"foo@bar.com\", \"password\": \"secret\"}}\n```\n\nExample response from the API:\n\n```\n201 Created\n{\"jwt\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\"}\n```\n\nTo make an authenticated request to your API, you need to pass the token via the request header:\n\n```\nAuthorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\nGET /my_resources\n```\n\nKnock 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.\n\n**NB:** HTTPS should always be enabled when sending a password or token in your request.\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 = Knock::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 used when the user is not found with the given credentials.\n\n```ruby\nKnock.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## 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## Contributing\n\n1. Fork it ( https://github.com/nsarno/knock/fork )\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## License\n\nMIT\n","funding_links":[],"categories":["Ruby","User","用户","Gems","Authentication and OAuth"],"sub_categories":["Authentication","认证","Authentication and OAuth"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsarno%2Fknock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnsarno%2Fknock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsarno%2Fknock/lists"}