Coder Social home page Coder Social logo

yeojz / otplib Goto Github PK

View Code? Open in Web Editor NEW
1.9K 15.0 128.0 8.1 MB

:key: One Time Password (OTP) / 2FA for Node.js and Browser - Supports HOTP, TOTP and Google Authenticator

Home Page: https://otplib.yeojz.dev

License: MIT License

JavaScript 26.09% Shell 1.84% HTML 0.18% CSS 2.04% TypeScript 69.85%
hotp hmac otp authenticator 2fa one-time-passwords two-factor-authentication two-factor google-authenticator nodejs

otplib's Introduction

otplib

Time-based (TOTP) and HMAC-based (HOTP) One-Time Password library

npm Build Status Coverage Status npm downloads TypeScript Support


About

otplib is a JavaScript One Time Password (OTP) library for OTP generation and verification.

It implements both HOTP - RFC 4226 and TOTP - RFC 6238, and are tested against the test vectors provided in their respective RFC specifications. These datasets can be found in the tests/data folder.

This library is also compatible with Google Authenticator, and includes additional methods to allow you to work with Google Authenticator.

Features

  • Typescript support
  • Class interfaces
  • Function interfaces
  • Async interfaces
  • Pluggable modules (crypto / base32)
    • crypto (node)
    • crypto-js
    • @ronomon/crypto-async
    • thirty-two
    • base32-encode + base32-decode
  • Presets provided
    • browser
    • default (node)
    • default-async (same as default, but with async methods)
    • v11 (adapter for previous version)

Quick Start

If you need to customise your base32 or crypto libraries, check out the In-Depth Guide and Available Packages

In Node.js

npm install otplib --save
import { authenticator } from 'otplib';

const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
// Alternative:
// const secret = authenticator.generateSecret();
// Note: .generateSecret() is only available for authenticator and not totp/hotp

const token = authenticator.generate(secret);

try {
  const isValid = authenticator.check(token, secret);
  // or
  const isValid = authenticator.verify({ token, secret });
} catch (err) {
  // Possible errors
  // - options validation
  // - "Invalid input - it is not base32 encoded string" (if thiry-two is used)
  console.error(err);
}

Please replace "authenticator" with "totp" or "hotp" depending on your requirements.

// For TOTP
import { totp } from 'otplib';
const token = totp.generate(secret);
const isValid = totp.check(token, secret);
const isValid = totp.verify({ token, secret });

// For HOTP
import { hotp } from 'otplib';
const token = hotp.generate(secret, counter);
const isValid = hotp.check(token, secret, counter);
const isValid = hotp.verify({ token, secret, counter });

For all available APIs, please refer to API Documentation.

In Browser

The browser preset is a self-contained umd module, and it is provided in a separate bundle.

npm install @otplib/preset-browser --save

The following is an example, where we are using the scripts hosted by unpkg.com.

<script src="https://unpkg.com/@otplib/preset-browser@^12.0.0/buffer.js"></script>
<script src="https://unpkg.com/@otplib/preset-browser@^12.0.0/index.js"></script>

<script type="text/javascript">
  // window.otplib.authenticator
  // window.otplib.hotp
  // window.otplib.totp
</script>

For more details, please refer to the @otplib/preset-browser documentation.

References

API / Demo Website

Version Links
v12.x Website / API / Readme
v11.x API / Readme
v10.x and below Available via git history

Versioning

This library follows semver. As such, major version bumps usually mean API changes or behavior changes. Please check upgrade notes for more information, especially before making any major upgrades.

To simplify releases, all packages within this repository have their versions synced. Therefore, if there are any releases or updates to a package, we will bump all packages.

Check out the release notes associated with each tagged versions in the releases page.

Release Type Version Pattern Command
Current / Stable 0.0.0 npm install otplib npm
Release Candidate 0.0.0-0 npm install otplib@next npm

Migrating from v11.x

v12.x is a huge architectural and language rewrite. Please check out the docs if you are migrating. A preset adapter is available to provide methods that behave like v11.x of otplib.

// Update
import { authenticator } from 'otplib'; // v11.x
// to
import { authenticator } from '@otplib/preset-v11';

// There should be no changes to your current code.
// However, deprecated or modified class methods will have console.warn.

Available Options

All instantiated classes will have their options inherited from their respective options generator. i.e. HOTP from hotpOptions, TOTP from totpOptions and Authenticator from authenticatorOptions.

All OTP classes have an object setter and getter method to override these default options.

For example,

import { authenticator, totp, hotp } from 'otplib';

// setting
authenticator.options = { digits: 6 };
totp.options = { digits: 6 };
hotp.options = { digits: 6 };

// getting
const opts = authenticator.options;
const opts = totp.options;
const opts = hotp.options;

// reset to default
authenticator.resetOptions();
totp.resetOptions();
hotp.resetOptions();

// getting all options, with validation
// and backfilled with library defaults
const opts = authenticator.allOptions();
const opts = totp.allOptions();
const opts = hotp.allOptions();

HOTP Options

Option Type Description
algorithm string The algorithm used for calculating the HMAC.
createDigest function Creates the digest which token is derived from.
createHmacKey function Formats the secret into a HMAC key, applying transformations (like padding) where needed.
digest string USE WITH CAUTION. Same digest = same token.
Used in cases where digest is generated externally. (eg: async use cases)
digits integer The length of the token.
encoding string The encoding that was used on the secret.
// HOTP defaults
{
  algorithm: 'sha1'
  createDigest: undefined, // to be provided via a @otplib/plugin-*
  createHmacKey: hotpCreateHmacKey,
  digits: 6,
  encoding: 'ascii',
}

TOTP Options

Note: Includes all HOTP Options

Option Type Description
epoch integer USE WITH CAUTION. Same epoch = same token.
Starting time since the UNIX epoch (seconds).
Epoch is JavaScript formatted. i.e. Date.now() or UNIX time * 1000
step integer Time step (seconds)
window integer,
[number, number]
Tokens in the previous and future x-windows that should be considered valid.
If integer, same value will be used for both.
Alternatively, define array: [past, future]
// TOTP defaults
{
  // ...includes all HOTP defaults
  createHmacKey: totpCreateHmacKey,
  epoch: Date.now(),
  step: 30,
  window: 0,
}

Authenticator Options

Note: Includes all HOTP + TOTP Options

Option Type Description
createRandomBytes function Creates a random string containing the defined number of bytes to be used in generating a secret key.
keyEncoder function Encodes a secret key into a Base32 string before it is sent to the user (in QR Code etc).
keyDecoder function Decodes the Base32 string given by the user into a secret.
// Authenticator defaults
{
  // ...includes all HOTP + TOTP defaults
  encoding: 'hex',
  createRandomBytes: undefined, // to be provided via a @otplib/plugin-*
  keyEncoder: undefined, // to be provided via a @otplib/plugin-*
  keyDecoder: undefined, // to be provided via a @otplib/plugin-*
}

Appendix

Type Definitions

TypeScript support was introduced in v10.0.0, which added type definitions over .js files.

As of v12.0.0, the library has been re-written in Typescript from the ground up.

Async Support

async support was introduced in v12.0.0 as an additional core library.

This was added as some libraries like expo.io or even the browser API (window.Crypto.subtle) started providing only async methods.

You to find more details in the core-async folder.

Browser Compatiblity

@otplib/preset-browser is a umd bundle with some node modules replaced to reduce the browser size.

The approximate size for the optimised, minified + gzipped bundle is 9.53KB. Paired with the gzipped browser buffer.js module, it would be about 7.65KB + 9.53KB = 17.18KB.

For more details, please refer to the @otplib/preset-browser documentation.

Length of Secrets

In RFC 6238, the secret / seed length for different algorithms are predefined:

HMAC-SHA1 - 20 bytes
HMAC-SHA256 - 32 bytes
HMAC-SHA512 - 64 bytes

As such, the length of the secret provided (after any decoding) will be padded and sliced according to the expected length for respective algorithms.

Google Authenticator

Difference between Authenticator and TOTP

The default encoding option has been set to hex (Authenticator) instead of ascii (TOTP).

RFC3548 Base32

Note: RFC4648 obseletes RFC 3548. Any encoders following the newer specifications will work.

Google Authenticator requires keys to be base32 encoded. It also requires the base32 encoder to be RFC 3548 compliant.

OTP calculation will still work should you want to use other base32 encoding methods (like Crockford's Base32) but it will NOT be compatible with Google Authenticator.

const secret = authenticator.generateSecret(); // base32 encoded hex secret key
const token = authenticator.generate(secret);

Displaying a QR code

You may want to generate and display a QR Code so that users can scan instead of manually entering the secret. Google Authenticator and similar apps take in a QR code that holds a URL with the protocol otpauth://, which you get from authenticator.keyuri.

Google Authenticator will ignore the algorithm, digits, and step options. See the keyuri documentation for more information.

If you are using a different authenticator app, check the documentation for that app to see if any options are ignored, which will result in invalid tokens.

While this library provides the "otpauth" uri, you'll need a library to generate the QR Code image.

An example is shown below:

// npm install qrcode
import qrcode from 'qrcode';
import { authenticator } from '@otplib/preset-default';

const user = 'A user name, possibly an email';
const service = 'A service name';

// v11.x and above
const otpauth = authenticator.keyuri(user, service, secret);

// v10.x and below
const otpauth = authenticator.keyuri(
  encodeURIComponent(user),
  encodeURIComponent(service),
  secret
);

qrcode.toDataURL(otpauth, (err, imageUrl) => {
  if (err) {
    console.log('Error with QR');
    return;
  }
  console.log(imageUrl);
});

Note: For versions v10.x and below, keyuri does not URI encode user and service. You'll need to do so before passing in the parameteres.

Getting Time Remaining / Time Used

Helper methods for getting the remaining time and used time within a validity period of a totp or authenticator token were introduced in v10.0.0.

authenticator.timeUsed(); // or totp.timeUsed();
authenticator.timeRemaining(); // or totp.timeRemaining();

// The start of a new token would be when:
// - timeUsed() === 0
// - timeRemaining() === step

Using with Expo

Expo contains modified crypto implmentations targeted at the platform. While otplib does not provide an expo specified package, with the re-architecture of otplib, you can now provide an expo native createDigest to the library.

Alternatively, you can make use of crypto provided by @otplib/plugin-crypto-js or the bundled browser umd module @otplib/preset-browser.

Pull Requests are much welcomed for a native expo implementation as well.

Exploring with local-repl

If you'll like to explore the library with local-repl you can do so as well.

# after cloning the repo:
npm run setup
npm run build
npx local-repl
# You should see something like:
# Node v8.9.4, local-repl 4.0.0
# otplib 10.0.0
# Context: otplib
# [otplib] >

[otplib] > secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD'
[otplib] > otplib.authenticator.generate(secret)

OTP Backup Codes

It is common for services to also provide a set of backup codes to authenticate and bypass the OTP step in the event that you are not able to access your 2FA device or have misplaced the device.

As this process is separate from the specifications for OTP, this library does not provide any backup code related verification logic, and thus would have to be implemented separately.

ECMAScript Modules

Node.js 12 introduced ECMAScript modules support behind the --experimental-modules flag, while Node.js v13 onwards shipped with it enabled by default.

As the feature is still listed as experimental, the packages in this project will continue to be released only in commonjs format for stability. Once the feature moves out of experimental status, we will look to support it.

At the moment, examples in the documentation assumes the use of transpilers (eg: babel). If you are using the Node's experimental import feature, some tweaks to the examples will be needed.

// If the example shows:
import { authenticator } from 'otplib';

// Then for:
// node 12 --experimental-modules
// node 13 onwards
// use the following:
import otplib from 'otplib';

const { authenticator } = otplib;

Contributors

Thanks goes to these wonderful people (emoji key):

Gerald Yeo
Gerald Yeo

๐Ÿ’ป ๐Ÿ“– ๐Ÿšง โš ๏ธ
Oliver Schneider
Oliver Schneider

๐Ÿ“–
Marc-Aurรจle DARCHE
Marc-Aurรจle DARCHE

๐Ÿ“–
Ahmed Hamdy (@shakram02)
Ahmed Hamdy (@shakram02)

๐Ÿ“–
Tony Brix
Tony Brix

๐Ÿ’ป ๐Ÿ“–
Plai
Plai

๐Ÿ“–

This project follows the all-contributors specification. Contributions of any kind welcome!

License

otplib is MIT licensed

otplib's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar encx avatar helloyou2012 avatar madarche avatar olsio avatar renovate-bot avatar shakram02 avatar uzitech avatar yeojz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

otplib's Issues

Why sometimes is invalid my token?

Hi, this is an strange behavior because sometimes is invalid the code without any modification. I used check() and verify() functions for it.

How to reproduce:

  1. Run next snippet some many times
const otplib = require('otplib')

let step = 5
let timing

otplib.authenticator.options = {
  step: step
}

const secret = otplib.authenticator.utils.encodeKey('This is my own private key without length restrictions!!')
const singleToken = otplib.authenticator.generate(secret)

console.log(singleToken)

setTimeout(() => {
  const isValid = otplib.authenticator.check(singleToken, secret)
  console.log(`Is valid first token: ${isValid}`)
}, 1001)

Details:

  • SO: Windows 10
  • Node: v8.9.3
  • Otplib: 9.0.0

Your .dependabot/config.yml contained invalid details

Dependabot encountered the following error when parsing your .dependabot/config.yml:

Automerging is not enabled for this account. You can enable it from the [account settings](https://app.dependabot.com/accounts/yeojz/settings) screen in your Dependabot dashboard.

Please update the config file to conform with Dependabot's specification using our docs and online validator.

Digits sometimes returning wrong length

Describe the bug
A clear and concise description of what the bug is.
With

authenticator.options = {
  digits: 6
};

I will sometimes get back 5 digits in length of a code, suggesting that codes might be getting generated with a leading 0. 023432

Whenever I verify 5 digit codes, they fail to verify.

Environment (please provide any relevant information):

  • OS: MacOS 12.14.4
  • Browser:
  • Node / Yarn: 11.13.0
  • Any frameworks:

Additional context
Add any other context about the problem here.

How to generate next token?

Hi,
The 'window ' option can make the next token valid if it's set to 1(or greater),
So how to generate the next token?
I use this lib to generate current token, and send it to another service to check if valid.
But every token can only use once in that service, and on that service the 'window' is 2,
so I want to generate the next token when I use current token twice.
It seems the 'epoch' option is useful, Can you give a example? I'm use it on a browser.
Thanks a lot.

Add brute force prevention

12 days = 12 * 24 * 60 * 60 seconds = 1 036 800 > 1 000 000.
1 try / sec will break code in 12 days, but really in 6 days(there is some math magic, believe me :) )
If TOTP is one factor it's fatal

Lets increase it to 20 years (10 really). If we limit speed to 1 try / 600 sec it will cause problem to user.
So first 50 attempts time waits
0 min x 10 tries
0,5 min x 10 tries
1 min x 10 tries
2 min x 10 tries
5 min x 10 tries
and then 10 min.

Another way is to require double code enter after 50 tries and limit timeout to 30 seconds.
In this case user will wait only 1,5 mins but combinations count will be 1 000 000 000 000, thats more than anyone can brute force :)

Out of sync

I scanned the code on the demo page but verification fails when I enter the code from my Google Authenticator app.

The code displayed on the demo page (and what otplib is verifying against) is always 1 code before the current code on my phone.

Basically after the time expires, I get a new code on my phone but the code displayed on the demo page is the previous code that was displayed on my phone.

So verification doesn't work.

I've tested with both iPhone and Android latest versions of Google Authenticator and both didn't verify.

Not sure what to do.

Any help is appreciated.

Thanks

resetOptions and options.crypto

Describe the bug
we have "Expecting options.crypto to have a createHmac function" error , when we resetOptions

To Reproduce
run the code

var otplib = require("otplib")
otplib.totp.resetOptions();
const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD'
const isValid = otplib.authenticator.check('12345', secret);

Expected behavior
If you comment otplib.totp.resetOptions(); we have no issue , but resetOptions don't reset truly an we have "Expecting options.crypto to have a createHmac function" error

Environment (please provide any relevant information):

  • OS: Windows
  • Browser:---
  • Node / Yarn: v10.14.2 / 1.13.0
  • Any frameworks: No

thirty-two does not have a license. change to base32-encode/base32-decode

Is your feature request related to a problem? Please describe.

thirty-two, the only dep of this package, doesn't have a license file in any version or a license field in package json. Because its not open source licensed i cant use this package =(

Describe the solution you'd like

i think that the recently updated and maintained base32-encode/base32-decode packages should be an adequate replacement for thirty-two.

Describe alternatives you've considered

ill have to pick another library but it seems that most depend on this uses library.

I've opened an issue on the repo for thirty-two and have not heard back from the maintainer yet.

Additional context

if you run npx js-green-licenses otplib you can test to see if you depend on anything that's not licensed.

otplib on ios with ionic

Hello, i'm having an issue with this lib on my ionic3 project.
For Android it builds and works perfectly, but on IOS it crash the app right after the splash screen, the screen keeps white.

that my info

`import authenticator from 'otplib/authenticator';

authenticator.options = {
algorithm: 'sha1',
step: 60,
digits: 6
};
var validationCode = authenticator.generate(this.user.userSecret);`

Ionic:

ionic (Ionic CLI) : 4.1.1 (/usr/local/lib/node_modules/ionic)
Ionic Framework : ionic-angular 3.9.2
@ionic/app-scripts : 3.1.10

Cordova:

cordova (Cordova CLI) : 8.0.0
Cordova Platforms : ios 4.5.5
Cordova Plugins : cordova-plugin-ionic-keyboard 2.1.2, cordova-plugin-ionic-webview 1.2.1, (and 23 other plugins)

System:

ios-deploy : 1.9.2
NodeJS : v10.6.0 (/usr/local/bin/node)
npm : 6.1.0
OS : macOS High Sierra
Xcode : Xcode 9.4.1 Build version 9F2000

my package.json
{ "name": "EasyChange", "version": "0.0.1", "author": "Ionic Framework", "homepage": "http://ionicframework.com/", "private": true, "scripts": { "clean": "ionic-app-scripts clean", "build": "ionic-app-scripts build", "lint": "ionic-app-scripts lint", "ionic:build": "ionic-app-scripts build", "ionic:serve": "ionic-app-scripts serve" }, "dependencies": { "@angular/animations": "5.2.11", "@angular/common": "5.2.11", "@angular/compiler": "5.2.11", "@angular/compiler-cli": "5.2.11", "@angular/core": "5.2.11", "@angular/forms": "5.2.11", "@angular/http": "5.2.11", "@angular/platform-browser": "5.2.11", "@angular/platform-browser-dynamic": "5.2.11", "@ionic-native/action-sheet": "^4.8.0", "@ionic-native/android-permissions": "^4.8.0", "@ionic-native/background-mode": "^4.8.0", "@ionic-native/barcode-scanner": "^4.8.0", "@ionic-native/camera": "^4.8.0", "@ionic-native/clipboard": "^4.8.0", "@ionic-native/contacts": "^4.8.0", "@ionic-native/core": "4.7.0", "@ionic-native/crop": "^4.8.0", "@ionic-native/device": "^4.8.0", "@ionic-native/facebook": "^4.8.0", "@ionic-native/fingerprint-aio": "^4.7.0", "@ionic-native/firebase": "^4.9.0", "@ionic-native/geolocation": "^4.8.0", "@ionic-native/google-plus": "^4.8.0", "@ionic-native/local-notifications": "^4.10.1", "@ionic-native/onesignal": "^4.8.0", "@ionic-native/sms": "^4.8.0", "@ionic-native/social-sharing": "^4.8.0", "@ionic-native/splash-screen": "4.7.0", "@ionic-native/status-bar": "4.7.0", "@ionic/pro": "1.0.20", "@ionic/storage": "2.1.3", "angular2-qrcode": "^2.0.1", "angularfire2": "^5.0.0-rc.11", "brmasker-ionic-3": "^1.1.0", "cordova-android": "^7.0.0", "cordova-clipboard": "^1.2.1", "cordova-ios": "4.5.5", "cordova-plugin-actionsheet": "^2.3.3", "cordova-plugin-add-swift-support": "^1.7.2", "cordova-plugin-android-permissions": "^1.0.0", "cordova-plugin-background-mode": "^0.7.2", "cordova-plugin-badge": "^0.8.7", "cordova-plugin-camera": "^4.0.3", "cordova-plugin-contacts": "^3.0.1", "cordova-plugin-crop": "^0.4.0", "cordova-plugin-device": "^2.0.2", "cordova-plugin-facebook4": "^2.3.0", "cordova-plugin-fingerprint-aio": "^1.3.8", "cordova-plugin-firebase": "^1.1.0", "cordova-plugin-geolocation": "^4.0.1", "cordova-plugin-googleplus": "^5.3.0", "cordova-plugin-ionic-keyboard": "^2.1.2", "cordova-plugin-ionic-webview": "^1.2.1", "cordova-plugin-local-notification": "^0.9.0-beta.2", "cordova-plugin-sms": "^1.0.5", "cordova-plugin-splashscreen": "^5.0.2", "cordova-plugin-statusbar": "git+https://github.com/apache/cordova-plugin-statusbar.git", "cordova-plugin-whitelist": "^1.3.3", "cordova-plugin-x-socialsharing": "^5.4.1", "cordova-sms-plugin": "^0.1.13", "es6-promise-plugin": "^4.2.2", "firebase": "^5.1.0", "hi-base32": "^0.5.0", "ionic-angular": "3.9.2", "ionicons": "3.0.0", "minimist": "^1.2.0", "moment": "^2.22.2", "onesignal-cordova-plugin": "^2.4.3", "otplib": "^10.0.0", "phonegap-plugin-barcodescanner": "^8.0.0", "rxjs": "5.5.11", "sw-toolbox": "3.6.0", "xml2js": "^0.4.19", "zone.js": "0.8.26" }, "devDependencies": { "@ionic/app-scripts": "3.1.10", "typescript": "~2.6.2" }, "description": "An Ionic project", "cordova": { "plugins": { "cordova-plugin-camera": {}, "onesignal-cordova-plugin": {}, "cordova-plugin-background-mode": {}, "cordova-plugin-android-permissions": {}, "cordova-clipboard": {}, "cordova-plugin-actionsheet": {}, "cordova-plugin-contacts": {}, "cordova-plugin-crop": {}, "cordova-plugin-device": {}, "cordova-plugin-facebook4": { "APP_ID": "", "APP_NAME": "", "ANDROID_SDK_VERSION": "4.+" }, "cordova-plugin-x-socialsharing": {}, "cordova-plugin-geolocation": { "GEOLOCATION_USAGE_DESCRIPTION": "To locate you" }, "cordova-plugin-googleplus": { "REVERSED_CLIENT_ID": "" }, "phonegap-plugin-barcodescanner": { "ANDROID_SUPPORT_V4_VERSION": "27.+" }, "cordova-plugin-whitelist": {}, "cordova-plugin-splashscreen": {}, "cordova-plugin-ionic-webview": {}, "cordova-plugin-ionic-keyboard": {}, "cordova-plugin-firebase": {}, "cordova-plugin-fingerprint-aio": { "FACEID_USAGE_DESCRIPTION": " " }, "cordova-sms-plugin": {}, "cordova-plugin-sms": {}, "cordova-plugin-local-notification": {}, "cordova-plugin-statusbar": {} }, "platforms": [ "android", "ios" ] } }

screen shot 2018-08-30 at 14 40 51
whatsapp image 2018-08-30 at 14 42 05

Tiny bug in site ( Clicking tab icon loads nothing )

Thank you so much for your efforts, your library is straight forward and easy to use, I just noticed that when I clicked on the icon (not the text, so basically you're clicking the span) of the tab 'verify,Get Secret`, ...etc the panel appears empty (which should include the qr-code or whatever matches).

To fix that, I added the data-tab-id attribute to the span having the same value as the tab. and it worked pretty well

 <li class="tab-item" data-tab-id='secret'>
            <a>
                <span class="icon is-small" data-tab-id='secret'><i class="fa fa-user-secret"></i></span>
                Get Secret
              </a>
          </li>

Unable to use with google authenticator

Hello,

I am unable to use this library to generate OTP matching Google Authenticator. The python version https://github.com/pyotp/pyotp works fine though.

Here's an example:

 <script src="https://yeojz.github.io/otplib/lib/otplib_commons.js"></script>
 <script src="https://rawgit.com/yeojz/otplib/gh-pages/lib/otplib.js"></script>

  var secret = "AAAABBBBCCCCDDDD";
  var token =  otplib.authenticator.generate(secret);
  console.log("secret is ", secret, "token is ", token);

This prints: secret is AAAABBBBCCCCDDDD token is 972373

The following python version matches the code generate by GA app:

>>> import pyotp 
>>> totp = pyotp.TOTP('AAAABBBBCCCCDDDD')
>>> totp.now()
u'580060'

Is there anything wrong with the above use of otplib for GA?

thanks
Santosh

Invalid 2FA Code, only when tests are ran on Mac Mini server.

Describe the bug
I use this library for 2FA in my automated tests. The application is stored on our own server (Mac Mini) and uses BrowserStack to run the tests, the 2FA code is always invalid.

Expected behavior
2FA code to be valid. If I run the them locally or on the cloud via my machine, 2FA always works.

Additional context
I understand this is a very niche issue. A point in the right direction would be much appreciated. Some code below:

const otplib = require('otplib');

const secret = "secret here"; 

module.exports.generate2FACode = function() {
    return otplib.authenticator.generate(secret);
}

async enterTwoFactorCode () {
        try {
            const element = await this.findE2eElement("twoFactorCodeInput");
            await this.focusOnElement(element);
            await element.clear();
            await element.sendKeys(twoFactorAuth.generate2FACode());
        } catch (error) {
            await this.logFailure();
            assert.fail("Unable to enter Two Factor code.");
        }
    }

how do I generate 16 character length secret key consistently?

Describe the bug

When generating a secret via const secret = authenticator.generateSecret()

the length of secret varies on every run.

To Reproduce
Steps to reproduce the behavior:
1.

const secret = authenticator.generateSecret()
console.log(secret);
console.log(secret.length);
  1. Run step 1 multiple times, secret.length will be different for every run

Expected behavior

I expect the secret generated of have a consistent length of 16

Details (please provide any relevant information):

  • otplib version: v12
  • os: linux
  • browser:
  • node / yarn: node v.12.13.0
  • frameworks (if any):

Additional context

the website ALWAYS generates a 16 character length string:

https://github.com/yeojz/otplib/blob/master/website/src/components/SecretStore.jsx#L19-L21

Inconsistense timer step

I am testing locally and I noticed that the time of the step that by default should be 30 seconds is not always respected when verifying.

To illustrate I made a simple setInterval() to check the token every 1 second.

let secret = otplib.authenticator.generateSecret()

const token = otplib.authenticator.generate(secret)
            
count = 1
setInterval(() => {
    $('#timmer').html(count)
    if ( otplib.authenticator.check(token, secret) ) {
        $('#result').html('Is Valid!').addClass('btn-success').removeClass('btn-primary')
    } else {
        $('#result').html('Is Invalid!').addClass('btn-danger').removeClass('btn-success')
    }
    count++
}, 1000)

I could not understand why sometimes it indicates invalid after 5 seconds, others after, 19, 24 ... anyway I could not identify a pattern.

Test case: CODEPEN

used in:

  • otplib-browser v7.0.0
  • Chrome 64.0.3282.140 (64bit) / Firefox 58.0 (64bit)
  • Window 8 (64bit)

How to generate a secret based on own data?

Hi,

First, this library is awesome. I want to know how to create my own seed based on personal data, like an id of database or another info, I'm checking otplib.authenticator.generateSecret but their only has one parameter to generate with length. Exist any way?

Authenticator verify method don't work

Describe the bug
After I've generated a QRCode with the secret generated by the authenticator encode method I use Google Authenticator to add it to my list. Everything works fine until here. But when I want to validate the token it is always invalid. I've tried a lot of things but now I don't know what to do next.

Here's my repo : https://github.com/FAGAL-Development/Phoenix

(The TFA part is in src/controllers/auth.ts)

Expected behavior
I would expect the token to be validated without any issues.

Environment (please provide any relevant information):

  • OS: Linux (Manjaro)
  • Node / Yarn: Yarn
  • Any frameworks: Express

Any help is appreciated ๐Ÿ’Ÿ

Publish Library for Polymer Components

Hello Team,

Could you please publish the OTPLIB to support the PWA Polymer Web components, this would enable the community to integrate HOTP using WEB Components. The Web components are Java Script files, needed to publish them in ES5, ES6, ES Modules to AMD Modules.

https://polymer-library.polymer-project.org/3.0/docs/tools/documentation

Below are the list of polymer Elements published by Polymer Team.
https://github.com/PolymerElements/app-layout
https://github.com/PolymerElements/app-localize-behavior
https://github.com/PolymerElements/app-media
https://github.com/PolymerElements/app-route
https://github.com/PolymerElements/app-storage
https://github.com/PolymerElements/font-roboto
https://github.com/PolymerElements/font-roboto-local
https://github.com/PolymerElements/gold-cc-cvc-input
https://github.com/PolymerElements/gold-cc-expiration-input
https://github.com/PolymerElements/gold-cc-input
https://github.com/PolymerElements/gold-phone-input
https://github.com/PolymerElements/gold-zip-input
https://github.com/PolymerElements/iron-a11y-announcer
https://github.com/PolymerElements/iron-a11y-keys
https://github.com/PolymerElements/iron-a11y-keys-behavior
https://github.com/PolymerElements/iron-ajax
https://github.com/PolymerElements/iron-autogrow-textarea
https://github.com/PolymerElements/iron-behaviors
https://github.com/PolymerElements/iron-checked-element-behavior
https://github.com/PolymerElements/iron-collapse
https://github.com/PolymerElements/iron-component-page
https://github.com/PolymerElements/iron-demo-helpers
https://github.com/PolymerElements/iron-doc-viewer
https://github.com/PolymerElements/iron-dropdown
https://github.com/PolymerElements/iron-fit-behavior
https://github.com/PolymerElements/iron-flex-layout
https://github.com/PolymerElements/iron-form
https://github.com/PolymerElements/iron-form-element-behavior
https://github.com/PolymerElements/iron-icon
https://github.com/PolymerElements/iron-icons
https://github.com/PolymerElements/iron-iconset
https://github.com/PolymerElements/iron-iconset-svg
https://github.com/PolymerElements/iron-image
https://github.com/PolymerElements/iron-input
https://github.com/PolymerElements/iron-jsonp-library
https://github.com/PolymerElements/iron-label
https://github.com/PolymerElements/iron-list
https://github.com/PolymerElements/iron-localstorage
https://github.com/PolymerElements/iron-location
https://github.com/PolymerElements/iron-media-query
https://github.com/PolymerElements/iron-menu-behavior
https://github.com/PolymerElements/iron-meta
https://github.com/PolymerElements/iron-overlay-behavior
https://github.com/PolymerElements/iron-pages
https://github.com/PolymerElements/iron-range-behavior
https://github.com/PolymerElements/iron-resizable-behavior
https://github.com/PolymerElements/iron-scroll-target-behavior
https://github.com/PolymerElements/iron-scroll-threshold
https://github.com/PolymerElements/iron-selector
https://github.com/PolymerElements/iron-swipeable-container
https://github.com/PolymerElements/iron-test-helpers
https://github.com/PolymerElements/iron-validatable-behavior
https://github.com/PolymerElements/iron-validator-behavior
https://github.com/PolymerElements/marked-element
https://github.com/PolymerElements/neon-animation
https://github.com/PolymerElements/paper-badge
https://github.com/PolymerElements/paper-behaviors
https://github.com/PolymerElements/paper-button
https://github.com/PolymerElements/paper-card
https://github.com/PolymerElements/paper-checkbox
https://github.com/PolymerElements/paper-dialog
https://github.com/PolymerElements/paper-dialog-behavior
https://github.com/PolymerElements/paper-dialog-scrollable
https://github.com/PolymerElements/paper-drawer-panel
https://github.com/PolymerElements/paper-dropdown-menu
https://github.com/PolymerElements/paper-fab
https://github.com/PolymerElements/paper-header-panel
https://github.com/PolymerElements/paper-icon-button
https://github.com/PolymerElements/paper-input
https://github.com/PolymerElements/paper-item
https://github.com/PolymerElements/paper-listbox
https://github.com/PolymerElements/paper-material
https://github.com/PolymerElements/paper-menu-button
https://github.com/PolymerElements/paper-progress
https://github.com/PolymerElements/paper-radio-button
https://github.com/PolymerElements/paper-radio-group
https://github.com/PolymerElements/paper-ripple
https://github.com/PolymerElements/paper-scroll-header-panel
https://github.com/PolymerElements/paper-slider
https://github.com/PolymerElements/paper-spinner
https://github.com/PolymerElements/paper-styles
https://github.com/PolymerElements/paper-swatch-picker
https://github.com/PolymerElements/paper-tabs
https://github.com/PolymerElements/paper-toast
https://github.com/PolymerElements/paper-toggle-button
https://github.com/PolymerElements/paper-toolbar
https://github.com/PolymerElements/paper-tooltip
https://github.com/PolymerElements/prism-element
https://github.com/PolymerElements/test-fixture

Thanks,
Ranganath.

Time Validity

Hello @yeojz

Thanks for module.

I am presently using the totp scheme for generating OTPs, Wanted to know what is the validity of the OTP. As in how long the OTP will be valid. There are times when the SMS service is busy and take a few seconds longer. In that case the OTP from totp scheme is invalid and the user needs to generate a new one. So, is there a way I can increase this time out by a few seconds (this is a silly question)?

I am aware that I can use hotp for perpetually valid token but wanted to stick with totp for its security.

Any help is appreciated.

Thanks,
Arvind.

how to use hotp verify

since hotp requires a counter, i am not able to find the correct API to verify HOTP. can you share some working samples?

backup codes

how can i generate backup codes for google authenticator?

Any Example for NodeJS

Hi
I want to use this lib in my node js project but there is no documentation for node js. The way is described is for typescript and I am not using typescript. When I try to use it according to node, I got error

const authenticator = require('otplib');
const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD';
const token = authenticator.generate(secret);

Getting Error: authenticator.generate is not a function

@yeojz @UziTech @madarche @encX @olsio

Not working on expo.io react native app

Describe the bug
Module crpyto not found when used in expo.io

To Reproduce
Steps to reproduce the behavior:

  1. Install expo
  2. expo init Project
  3. Edit App.js and paste code below
import otplib from 'otplib'

const secret = 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD'
const token = otplib.generate(secret) // 556443
``

**Expected behavior**
Should not have errors

**Environment (please provide any relevant information):**
 - OS: MacOs Mojave
 - Node / Yarn: node8.6
 - Any frameworks: Expo/React Native

SyntaxError: The requested module 'otplib' does not provide an export named 'authenticator'

Describe the bug
Taken straight from the README example, when importing totp it gives syntaxerror

To Reproduce
Steps to reproduce the behavior:

  1. Code import { totp } from "otplib"; crashes

Screenshots
If applicable, add screenshots to help explain your problem.

Details (please provide any relevant information):

  • otplib version: 12.0.1
  • os: win10
  • browser:
  • node / yarn: 12.13.1
  • frameworks (if any):

Additional context
node is started with experimental modules flag to enable ecmascript modules

TypeScript: verify and check in authenticator does not reflect Base32 key.

Describe the bug

authenticator.verify and authenticator.check typings don't reflect the need for Base32 key.

To Reproduce

Expected behavior

.verify / .check should also reflect Base32 encoded state.

Screenshots

Details (please provide any relevant information):

  • otplib version: 12.0.1
  • os:
  • browser:
  • node / yarn:
  • frameworks (if any):

Additional context

Unexpected token =

I am getting the below error on adding otplib to my project through npm

/home/thooyavan/api/node_modules/otplib/hotp.js:21
set options(opt = {}) {
^

SyntaxError: Unexpected token =
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:374:25)
at Module._extensions..js (module.js:417:10)
at Object.require.extensions.(anonymous function) [as .js] (/home/thooyavan/api/node_modules/babel-register/lib/node.js:152:7)
at Module.load (module.js:344:32)
at Function.Module._load (module.js:301:12)
at Module.require (module.js:354:17)
at require (internal/module.js:12:17)
at Object. (/home/thooyavan/api/node_modules/otplib/otplib.js:14:28)
at Module._compile (module.js:410:26)

Someone Kindly help me out

authenticator.keyuri does not uri encode user and service

Describe the bug
keyuri should probably uri encode user and service to allow spaces etc, although this would be a breaking change. Or at least mention in the documentation that uri encoding is needed.

To Reproduce
otplib.authenticator.keyuri("{secret}", "acme co", "JBSWY3DPEHPK3PXP")

Not working in IE11

Describe the bug
In IE 11, I get the following error:

'SCRIPT1006: Expected ')'
File: app.bundle.js, Line: 53467, Column: 30'

Which leads to this function:
function hotpOptions(options = {}) { return Object.assign( { algorithm: 'sha1', createHmacSecret: hotpSecret, crypto: null, digits: 6, encoding: 'ascii' }, options ); }

Expected behavior
That it works in IE 11

Environment (please provide any relevant information):

  • OS: Windows 7
  • Browser: IE 11
  • Node / Yarn: v8.15.0
  • Any frameworks: React, Webpack

Switch back from yarn?

Npm now supports package.lock. And for this repo's use case, seems to suffice.

caveat: >npm5

TypeError: otplib_1.otplib is undefined

Hello,

I'm new in angular and run into this Error: TypeError: otplib_1.otplib is undefined

I have install the package

npm install otplib --save

I have also tryed

npm install otplib@next --save

I have it included with following code:

import { otplib } from "otplib";

At this point "vs code" tells me that there is a definition file (*.d.ts) missing.


I try to use the Authenenticator class:

createSecret()
  {
    let authenticator = new otplib.Authenenticator();
    authenticator.options = { crypto }
    const secret = authenticator.generateSecret();
    return secret;
  }

I have alseo tryed:

createSecret()
  {
    const secret = otplib.authenticator.generateSecret();
    return secret;
  }

My major question is, what do I wrong?
I try to follow your instructions at https://yeojz.github.io/otplib/docs/ but it doen't work.

Please, give me an instruction that it work.

window is not defined with mocha, jsdom, and enzyme

Describe the bug
I'm having problems getting this library to work with mocha/enzyme tests.

It seems no matter what i do to try and set up jsdom to provide the window object before this library is imported I get ReferenceError: window is not defined

I'm following the guide here:
https://github.com/airbnb/enzyme/blob/master/docs/guides/jsdom.md

Any pointers would be appreciated.

To Reproduce
Steps to reproduce the behavior:

  1. create a mocha/enzyme test project that uses jsdom to create the window object
  2. import otplib from 'otplib/otplib-browser' in your code

Can't include otplib via import

Steps to reproduce the behavior:
1.import otplib from 'otplib'; console.log(otplib);//returns undefined
2.const otplib = require('otplib'); works fine

Environment (please provide any relevant information):

  • OS: MacOSX
  • Node / Yarn: Yarn
  • Any frameworks: Express

Currently not usable with create-react-native-app

I was trying to use the library in a react-native app, created by the create-react-native-app script. The problem is that this will run the app in the expo.io container which does not expose the native crypto module causing Unable to resolve module crypto.

As far as I can see the otplib is already doing some magic to check if this runs in browser or node to switch out the randomBytes routine's implementation. I am sure adding another detection branch for react-native/expo could enable otblib run in that environment as well by using browserfy-crypto implemenations.

I already tried to use the crypto-shim proposed for react-native but this requires the ejection of the project into a proper react-native application to link the native random bytes implementation. With this I am loosing the convenience of the expo client and libs.
https://github.com/mvayngrib/react-native-crypto

I will try to create a pull request if I find a solution but you might see an easy fix.

Attached an example project. Running it in the simulator or on an device will trigger the fault. Running it in node is fine.
otp-crypto-test.zip

how do I get 16 secret key?

hello.
I wonder how to get secret key.
I saw demo secret on your demo site.
I want it as follow.

WNSI7324JNTARPQF

somebody help me!

5.2 RFC 6238 past time-step window support

The validation system should compare OTPs not only with the receiving timestamp but also the past timestamps that are within the transmission delay.

Code may change while user is entering code. For this situation system check actual and past code. No need to wait for time-window change

Add parameter for it. Suggest to set it to 1 window by default

Token not matched with the Google Authenticator app

I have gone through your otplib it was really useful, thanks for such an amazing tutorials.

i'm getting the qr-code successfully. but if i run the code it generating the TOKEN for every minute That's fine, But if i scan the code from the Google Authenticator App it generating different number. Actually So both the code are not same.

Thanks in advance.....

I want to know how to compare the Mobile App Token with my node js code. Please give any suggestion.

not able to build my app

getting following error

ERROR in node_modules/otplib/index.d.ts(6,67): error TS2304: Cannot find name 'Buffer'.

.

.

Token check is using parseFloat

Actual behavior
If i call the function verify with a valid token it returns true

const token = "1234"
authenticator.verify({ token, secret }))

If i call the function verify with a valid token followed by any letter it returns true

const token = "1234abc"
authenticator.verify({ token, secret }))

If i call the function verify with a any letter followed by a valid token it returns false

const token = "abc1234"
authenticator.verify({ token, secret }))

Expected behavior
The expected behavior is to return true only in the first case

Additional context
Digging into the lib code i have found that the token comparison between the one provided by the user and the one generated by the lib is made using the following

function isSameToken(token1, token2) {
  return parseFloat(token1) === parseFloat(token2);
}

Applying parseFloat to 1234abc will return 1234, applying it to acd1234 will rerturn NaN i think that in both cases 1234abc and acd1234 the function should return false since the provided token is actually not the same as the one generated by the lib

Google authenticator token won't match

I cannot realize what could be problem. I have read docs couple of times but it still throws false from authenticator.verify()

// foundUser is fetched user from DB

Token provider func:

const secret = otplib.authenticator.generate();

    foundUser.secret = secret;
    await foundUser.save();

    const otpauth = otplib.authenticator.keyuri(
      foundUser.email,
      "Remind Me",
      secret
    );
    const qrCode = await QR.toDataURL(otpauth);

    if (qrCode) {
      console.log(qrCode);
      return {
        qrCodeUri: qrCode
      };
    }

Token validator:

  console.log(`Expected: ${otplib.authenticator.generate(foundUser.secret)}`);
  console.log(`User: ${userToken}`);
  
const verified = otplib.authenticator.verify({
    token: userToken,
    secret: foundUser.secret
  });

  if (verified) {
    const token = jwt.sign(
      {
        email,
        username: foundUser.username
      },
      jwt_secret
    );
    return {
      token
};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.