{"id":18336312,"url":"https://github.com/launchpadlab/token-master","last_synced_at":"2025-07-14T17:40:12.208Z","repository":{"id":62559203,"uuid":"83079790","full_name":"LaunchPadLab/token-master","owner":"LaunchPadLab","description":"Minimal and Simple user management for Ruby and Rails applications.","archived":false,"fork":false,"pushed_at":"2023-04-08T16:48:49.000Z","size":178,"stargazers_count":17,"open_issues_count":5,"forks_count":1,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-07-02T21:52:56.987Z","etag":null,"topics":["confirm","devise","invite","launchpad-lab","rails","ruby","token","user-management"],"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/LaunchPadLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2017-02-24T20:25:22.000Z","updated_at":"2023-01-31T16:48:11.000Z","dependencies_parsed_at":"2024-11-08T22:46:07.992Z","dependency_job_id":null,"html_url":"https://github.com/LaunchPadLab/token-master","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/LaunchPadLab/token-master","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaunchPadLab%2Ftoken-master","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaunchPadLab%2Ftoken-master/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaunchPadLab%2Ftoken-master/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaunchPadLab%2Ftoken-master/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LaunchPadLab","download_url":"https://codeload.github.com/LaunchPadLab/token-master/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LaunchPadLab%2Ftoken-master/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265327198,"owners_count":23747702,"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":["confirm","devise","invite","launchpad-lab","rails","ruby","token","user-management"],"created_at":"2024-11-05T20:07:26.505Z","updated_at":"2025-07-14T17:40:12.149Z","avatar_url":"https://github.com/LaunchPadLab.png","language":"Ruby","readme":"\u003cimg src=\"badge.png\" alt=\"Token Master Logo\" width=\"150\"/\u003e\n\u003ch1\u003eToken Master\u003c/h1\u003e\n\n[![GitHub](http://img.shields.io/badge/github-launchpadlab/token_master-blue.svg)](http://github.com/launchpadlab/token_master)\n[![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/token_master)\n[![Inline docs](http://inch-ci.org/github/LaunchPadLab/token-master.svg?branch=master)](http://inch-ci.org/github/LaunchPadLab/token-master)\n[![Gem Version](https://badge.fury.io/rb/token_master.svg)](https://badge.fury.io/rb/token_master)\n[![Build Status](https://travis-ci.org/LaunchPadLab/token-master.svg?branch=master)](https://travis-ci.org/LaunchPadLab/token-master)\n[![Test Coverage](https://codeclimate.com/github/LaunchPadLab/token-master/badges/coverage.svg)](https://codeclimate.com/github/LaunchPadLab/token-master/coverage)\n[![License](http://img.shields.io/badge/license-MIT-yellowgreen.svg)](#license)\n\nSimple token logic for providing (temporary) restricted access.\nNo routing, views, controllers, or mailers, just logic that you can use wherever and whenever you want.\n\nTokens can be used for any action that needs the access, such as inviting, confirming, or resetting passwords. These actions can be considered *tokenable actions*.\n\nTokenable actions can be attributed to any model, not just users. These models then become *tokenable models*.\n\n* [Quick Start](#quick-start)\n* [Details](#details)\n* [FAQ](#faq)\n* [Motivation](#motivation)\n\n## Quick Start\n\n### Installation\nAdd this line to your application's Gemfile:\n\n`gem 'token_master'`\n\nAnd then execute:\n\n`$ bundle`\n\nOr install it yourself as:\n\n`$ gem install token_master`\n\n### Usage\n\n##### These examples assume Rails 5, but anything \u003e= 4 will work\n\nLet's say you want to add email confirmation flow to your User. Your **tokenable model** then is the **User** model, and the **tokenable action** might be something like *confirm* (although you can name it anything, as long as you are consistent).\n\n1. Create and run a migration to add the necessary columns to the `users` table like so:\n```\nbundle exec rails generate token_master User confirm\nbundle exec rails db:migrate\n```\n\n2. Add the Token Master `token_master` hook to the User class, and pass in the symbol for your *tokenable action*:\n\n```\nclass User \u003c ApplicationRecord\n  token_master :confirm\nend\n```\n\n3. Somewhere during the signup flow, generate and send the token:\n\n```\nclass UsersController \u003c ApplicationController\n\n  def create\n\n    # Creating the user is up to you, here is an example\n    user = User.create!(\n      email: params[:email],\n      password: params[:password],\n      password_confirmation: params[:password_confirmation]\n    )\n\n    # Generate and save a unique token on the new user\n    token = user.set_confirm_token!\n\n    # Mark the token as sent\n    user.send_confirm_instructions! do\n      # Sending the email is up to you, by passing a block here:\n      UserMailer.send_confirm(user) # or some other logic\n    end\n  end\n\n  def resend_confirmation_instructions\n\n    # if you have a 'resend instructions?' flow you can generate a new token and send instructions again in one step\n    user.resend_confirm_instructions! do\n      # Sending the email is up to you, by passing a block here:\n      UserMailer.send_confirm(user) # or some other logic\n    end\n  end\n\nend\n```\n\n4. Somewhere during the confirmation flow, find and confirm the user:\n\n```\nclass UsersController \u003c ApplicationController\n  def confirm\n\n    # finds the user by the token, and mark the token as completed\n    user = User.confirm_by_token!(params[:token])\n\n    ...\n\n  end\nend\n```\n\n## Details\n\nLet's revisit the Quick Start and fill in the details.\n\n### The Generator\nWhen you ran the generator\n```\nbundle exec rails generate token_master User confirm\n```\nyou provided two arguments:\n  * `User` - The class name of the model to which you are adding the *tokenable action*\n  * `confirm` - The name of the *tokenable action*\n\nBoth of these could be anything, as long as you use the same class and name later on. If you like, you can create multiple *tokenables* at the same time, just add more space-separated *tokenable* names when calling the generator:\n```\nbundle exec rails generate token_master User confirm invite reset\n```\n\nRunning the generator does two things:\n1. Creates a migration file in `#{Rails.root}/db/migrate` that looks like:\n\n```\nclass AddConfirmTokenableToUsers \u003c ActiveRecord::Migration[5.0]\n  def change\n    add_column :users, :confirm_token,        :string,    default: nil\n    add_column :users, :confirm_created_at,   :timestamp, default: nil\n    add_column :users, :confirm_completed_at, :timestamp, default: nil\n    add_column :users, :confirm_sent_at,      :timestamp, default: nil\n\n    add_index :users, :confirm_token\n  end\nend\n```\n\nwhere the `:users` table is determined from the `User` argument and `:confirm_*` is determined from the `confirm` argument.\n\n2. Creates an initializer `#{Rails.root}/config/initializers/token_master.rb` that looks like:\n\n```\nTokenMaster.config do |config|\n  # Set up your configurations for each *tokenable* using the methods at the bottom of this file.\n  # Example: For `confirm` logic:\n  #\n  # Default values:\n  #   token_lifetime  = 15 # days\n  #   required_params = []\n  #   token_length    = 20 # characters\n\n  config.add_tokenable_options :confirm,\n    token_lifetime:  15, # days\n    required_params: [:email],\n    token_length:    30 # characters\nend\n```\nThe default values will be used unless you configure them otherwise. These options can be set for each *tokenable action*.\n\n### The Model\nWhen you added the Token Master hook and  *tokenable action* to your model\n```\nclass User \u003c ApplicationRecord\n  token_master :confirm\nend\n```\njust make sure the class `User` and *tokenable(s)* `:confirm` (this can be multiple tokenables) match what you used in your generator.\n\nEx.\n```\ntoken_master :confirm, :invite, :reset\n```\n\n1. The `token_master` hook is included automatically by Token Master in your `ApplicationRecord` base class.\n\nHowever, if necessary, you can add this yourself by including the following in your class:\n```\ninclude TokenMaster::Model\n```\nThis adds the `token_master` class method we used above, and you can make the same calls we described in the `confirm` example above.\n\n2. When you call the `token_master` class method, for each *tokenable action* you provide, a handful of methods are added to the class for each *tokenable action*, and named accordingly.\n\nAssuming the *tokenable action* below is `confirm`, the methods would look like this:\n\nInstance methods\n* `set_confirm_token!`\n* `send_confirm_instructions!`\n* `resend_confirm_instructions!`\n* `confirm_status`\n* `force_confirm!`\n\nClass methods\n* `confirm_by_token!`\n\nIn addition to the three you have already seen in action, there is also:\n\n`confirm_status` - returns the current status of the *tokenable action*. This is one of:\n* 'no token'\n* 'created'\n* 'sent'\n* 'completed'\n* 'expired'\n\n`force_confirm!` - forcibly completes the given *tokenable action*\n\nSee the [Api Docs][docs] for more details.\n\n## Advanced\nSometimes in order to redeem a token, we want to make sure some additional information is present and possibly save that to our model.\nFor example, when implementing a password reset flow, we want to update the User with the new password and make sure it's valid.\n\nAssuming we are using `has_secure_password` or something similar all we need to do is:\n1. Configure the *tokenable action* to require these fields when redeeming the token\n\n**../initializers/token_master.rb**\n```\nTokenMaster.config do |config|\n  config.add_tokenable_options :reset_password,\n    token_lifetime:  1\n    required_params: [:password, :password_confirmation]\n    token_length:    30\nend\n```\n\n2. Include those parameters when redeeming the token (If you don't you will get an error!)\n```\nUser.reset_password_by_token!(\n  token,\n  password: password,\n  password_confirmation: password_confirmation\n)\n```\n\nUnder the hood, Token Master calls `update!` on the model, so if the model is not valid, it won't be saved and the token will not be redeemed.\n\n## FAQ\n\n### Can I use this without Rails?\nYes! However, there is a small dependency on ActiveRecord, see below.\n\n### Can I use this without ActiveRecord?\nAlmost! There is only a slight dependence on a few ActiveRecord methods and its on our radar to refactor this a bit. In the meantime, a workaround is to make sure the class you are using implements `update`, `update!`, `save`, and `find_by`. In addition, you have to either add Token Master to your class with `include TokenMaster::Model` or use the Token Master core module explicitly:\n\n`TokenMaster::Core.set_token!(User, :confirm)` (which is equivalent to `user.set_confirm_token!(token)`)\n\nSee the [Api Docs][docs] for more details.\n\n### Who is Launchpad Lab?\nWe are product builders, check us out at [Launchpad Lab][lpl]\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/LaunchpadLab/token-master.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n---------------------------\n\u003c!-- Links --\u003e\n[devise]: https://github.com/plataformatec/devise\n[sorcery]: https://github.com/Sorcery/sorcery\n[docs]: http://www.rubydoc.info/gems/token_master\n[lpl]: https://launchpadlab.com/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaunchpadlab%2Ftoken-master","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaunchpadlab%2Ftoken-master","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaunchpadlab%2Ftoken-master/lists"}