{"id":13540070,"url":"https://github.com/mdp/rotp","last_synced_at":"2025-05-14T11:04:33.778Z","repository":{"id":37934487,"uuid":"1362437","full_name":"mdp/rotp","owner":"mdp","description":"Ruby One Time Password library","archived":false,"fork":false,"pushed_at":"2025-01-06T22:27:09.000Z","size":282,"stargazers_count":1621,"open_issues_count":9,"forks_count":465,"subscribers_count":25,"default_branch":"main","last_synced_at":"2025-05-07T08:59:58.123Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://rubydoc.info/github/mdp/rotp/master/frames","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/mdp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"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":"2011-02-13T18:20:59.000Z","updated_at":"2025-05-05T19:44:14.000Z","dependencies_parsed_at":"2024-06-18T10:57:30.381Z","dependency_job_id":"edbb1786-f1ba-42bb-8a28-672b0c13ceb5","html_url":"https://github.com/mdp/rotp","commit_stats":{"total_commits":227,"total_committers":46,"mean_commits":4.934782608695652,"dds":"0.42731277533039647","last_synced_commit":"1fbd30d94e5c986b0e252e3257b2f345735439ce"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdp%2Frotp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdp%2Frotp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdp%2Frotp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mdp%2Frotp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mdp","download_url":"https://codeload.github.com/mdp/rotp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252860253,"owners_count":21815487,"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-08-01T09:01:39.168Z","updated_at":"2025-05-14T11:04:33.727Z","avatar_url":"https://github.com/mdp.png","language":"Ruby","funding_links":[],"categories":["Ruby","\u003ca id=\"862af330f45f21fbb0d495837fc7e879\"\u003e\u003c/a\u003e工具","Authentication"],"sub_categories":["\u003ca id=\"20bf2e2fefd6de7aadbf0774f4921824\"\u003e\u003c/a\u003e未分类-Password"],"readme":"## Webauthn and the future of 2FA\n\nAlthough this library will continue to be maintained, if you're implementing a 2FA solution today, you should take a look at [Webauthn](https://webauthn.guide/). It doesn't involve shared secrets and it's supported by most modern browsers and operating systems.\n\n### Ruby resources for Webauthn\n\n- [Multi-Factor Authentication for Rails With WebAuthn and Devise](https://www.honeybadger.io/blog/multi-factor-2fa-authentication-rails-webauthn-devise/)\n- [Webauthn Ruby Gem](https://github.com/cedarcode/webauthn-ruby)\n- [Rails demo app with Webauthn](https://github.com/cedarcode/webauthn-rails-demo-app)\n\n----\n\n# The Ruby One Time Password Library\n\n[![Build Status](https://github.com/mdp/rotp/actions/workflows/test.yaml/badge.svg)](https://github.com/mdp/rotp/actions/workflows/test.yaml)\n[![Gem Version](https://badge.fury.io/rb/rotp.svg)](https://rubygems.org/gems/rotp)\n[![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](https://www.rubydoc.info/github/mdp/rotp/master)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/mdp/rotp/blob/master/LICENSE)\n\n\nA ruby library for generating and validating one time passwords (HOTP \u0026 TOTP) according to [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226) and [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238).\n\nROTP is compatible with [Google Authenticator](https://github.com/google/google-authenticator) available for [Android](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2) and [iPhone](https://itunes.apple.com/en/app/google-authenticator/id388497605) and any other TOTP based implementations.\n\nMany websites use this for [multi-factor authentication](https://www.youtube.com/watch?v=17rykTIX_HY), such as GMail, Facebook, Amazon EC2, WordPress, and Salesforce. You can find a more complete [list here](https://en.wikipedia.org/wiki/Google_Authenticator#Usage).\n\n## Dependencies\n\n* OpenSSL\n* Ruby 2.3 or higher\n\n## Breaking changes\n\n### Breaking changes in \u003e= 6.0\n\n- Dropping support for Ruby \u003c2.3\n\n### Breaking changes in \u003e= 5.0\n\n- `ROTP::Base32.random_base32` is now `ROTP::Base32.random` and the argument\n  has changed from secret string length to byte length to allow for more\n  precision. There is an alias to allow for `random_base32` for the time being.\n- Cleaned up the Base32 implementation to match Google Authenticator's version.\n\n### Breaking changes in \u003e= 4.0\n\n- Simplified API\n  - `verify` now takes options for `drift` and `after`,`padding` is no longer an option\n  - `verify` returns a timestamp if true, nil if false\n- Dropping support for Ruby \u003c 2.0\n- Docs for 3.x can be found [here](https://github.com/mdp/rotp/tree/v3.x)\n\n## Installation\n\n```bash\ngem install rotp\n```\n\n## Library Usage\n\n### Time based OTP's\n\n```ruby\ntotp = ROTP::TOTP.new(\"base32secret3232\", issuer: \"My Service\")\ntotp.now # =\u003e \"492039\"\n\n# OTP verified for current time - returns timestamp of the current interval\n# period.\ntotp.verify(\"492039\") # =\u003e 1474590700\n\nsleep 30\n\n# OTP fails to verify - returns nil\ntotp.verify(\"492039\") # =\u003e nil\n```\n\n### Counter based OTP's\n\n```ruby\nhotp = ROTP::HOTP.new(\"base32secretkey3232\")\nhotp.at(0) # =\u003e \"786922\"\nhotp.at(1) # =\u003e \"595254\"\nhotp.at(1401) # =\u003e \"259769\"\n\n# OTP verified with a counter\nhotp.verify(\"259769\", 1401) # =\u003e 1401\nhotp.verify(\"259769\", 1402) # =\u003e nil\n```\n\n### Preventing reuse of Time based OTP's\n\nBy keeping track of the last time a user's OTP was verified, we can prevent token reuse during\nthe interval window (default 30 seconds)\n\nThe following is an example of this in action:\n\n```ruby\nuser = User.find(someUserID)\ntotp = ROTP::TOTP.new(user.otp_secret)\ntotp.now # =\u003e \"492039\"\n\n# Let's take a look at the last time the user authenticated with an OTP\nuser.last_otp_at # =\u003e 1432703530\n\n# Verify the OTP\nlast_otp_at = totp.verify(\"492039\", after: user.last_otp_at) #=\u003e 1472145760\n# ROTP returns the timestamp(int) of the current period\n\n# Store this on the user's account\nuser.update(last_otp_at: last_otp_at)\n\n# Someone attempts to reuse the OTP inside the 30s window\nlast_otp_at = totp.verify(\"492039\", after: user.last_otp_at) #=\u003e nil\n# It fails to verify because we are still in the same 30s interval window\n```\n\n### Verifying a Time based OTP with drift\n\nSome users may enter a code just after it has expired. By adding 'drift' you can allow\nfor a recently expired token to remain valid.\n\n```ruby\ntotp = ROTP::TOTP.new(\"base32secret3232\")\nnow = Time.at(1474590600) #2016-09-23 00:30:00 UTC\ntotp.at(now) # =\u003e \"250939\"\n\n# OTP verified for current time along with 15 seconds earlier\n# ie. User enters a code just after it expired\ntotp.verify(\"250939\", drift_behind: 15, at: now + 35) # =\u003e 1474590600\n# User waits too long. Fails to validate previous OTP\ntotp.verify(\"250939\", drift_behind: 15, at: now + 45) # =\u003e nil\n```\n\n### Generating a Base32 Secret key\n\n```ruby\nROTP::Base32.random  # returns a 160 bit (32 character) base32 secret. Compatible with Google Authenticator\n```\n\nNote: The Base32 format conforms to [RFC 4648 Base32](http://en.wikipedia.org/wiki/Base32#RFC_4648_Base32_alphabet)\n\n### Generating QR Codes for provisioning mobile apps\n\nProvisioning URI's generated by ROTP are compatible with most One Time Password applications, including\nGoogle Authenticator.\n\n```ruby\ntotp = ROTP::TOTP.new(\"base32secret3232\", issuer: \"My Service\")\ntotp.provisioning_uri(\"alice@google.com\") # =\u003e 'otpauth://totp/My%20Service:alice%40google.com?secret=base32secret3232\u0026issuer=My%20Service'\n\nhotp = ROTP::HOTP.new(\"base32secret3232\", issuer: \"My Service\")\nhotp.provisioning_uri(\"alice@google.com\", 0) # =\u003e 'otpauth://hotp/My%20Service:alice%40google.com?secret=base32secret3232\u0026issuer=My%20Service\u0026counter=0'\n```\n\nThis can then be rendered as a QR Code which the user can scan using their mobile phone and the appropriate application.\n\n#### Working example\n\nScan the following barcode with your phone, using Google Authenticator\n\n![QR Code for OTP](https://cloud.githubusercontent.com/assets/2868/18771262/54f109dc-80f2-11e6-863f-d2be62ee587a.png)\n\nNow run the following and compare the output\n\n```ruby\nrequire 'rubygems'\nrequire 'rotp'\ntotp = ROTP::TOTP.new(\"JBSWY3DPEHPK3PXP\")\np \"Current OTP: #{totp.now}\"\n```\n\n### Testing\n\n```bash\nbundle install\nbundle exec rspec\n```\n\n### Testing with Docker\n\nIn order to make it easier to test against different ruby version, ROTP comes\nwith a set of Dockerfiles for each version that we test against in Travis\n\n```bash\ndocker build -f Dockerfile-2.6 -t rotp_2.6 .\ndocker run --rm -v $(pwd):/usr/src/app rotp_2.6\n```\n\nAlternately, you may use docker-compose to run all the tests:\n\n```\ndocker-compose up\n```\n\n## Executable Usage\n\nThe rotp rubygem includes CLI version to help with testing and debugging\n\n```bash\n# Try this to get an overview of the commands\nrotp --help\n\n# Examples\nrotp --secret p4ssword                       # Generates a time-based one-time password\nrotp --hmac --secret p4ssword --counter 42   # Generates a counter-based one-time password\n```\n\n## Contributors\n\nHave a look at the [contributors graph](https://github.com/mdp/rotp/graphs/contributors) on Github.\n\n## License\n\nMIT Copyright (C) 2019 by Mark Percival, see [LICENSE](https://github.com/mdp/rotp/blob/master/LICENSE) for details.\n\n## Other implementations\n\nA list can be found at [Wikipedia](https://en.wikipedia.org/wiki/Google_Authenticator#Implementations).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmdp%2Frotp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmdp%2Frotp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmdp%2Frotp/lists"}