{"id":27247186,"url":"https://github.com/farshidbeheshti/xotp","last_synced_at":"2025-10-14T02:04:39.063Z","repository":{"id":261666206,"uuid":"881569844","full_name":"farshidbeheshti/xotp","owner":"farshidbeheshti","description":"A One-Time Password library for Node.js, Deno and Bun. Ideal for use in  2FA / MFA systems, with support for popular authentication apps including Google Authenticator.","archived":false,"fork":false,"pushed_at":"2025-04-09T20:13:51.000Z","size":173,"stargazers_count":17,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"dev","last_synced_at":"2025-04-10T22:48:47.131Z","etag":null,"topics":["bunjs","deno","google-authenticator","hotp","nodejs","otp","otp-generator","otp-verification","totp","totp-generator","two-factor-authentication","two-step-authentication"],"latest_commit_sha":null,"homepage":"https://xotp.dev","language":"TypeScript","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/farshidbeheshti.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2024-10-31T20:41:24.000Z","updated_at":"2025-04-10T19:41:48.000Z","dependencies_parsed_at":"2024-11-24T21:25:00.603Z","dependency_job_id":"1dc1762e-39fb-4a50-8caf-c704ba03e147","html_url":"https://github.com/farshidbeheshti/xotp","commit_stats":null,"previous_names":["farshidbeheshti/otp","farshidbeheshti/xotp"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farshidbeheshti%2Fxotp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farshidbeheshti%2Fxotp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farshidbeheshti%2Fxotp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farshidbeheshti%2Fxotp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/farshidbeheshti","download_url":"https://codeload.github.com/farshidbeheshti/xotp/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248312197,"owners_count":21082637,"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":["bunjs","deno","google-authenticator","hotp","nodejs","otp","otp-generator","otp-verification","totp","totp-generator","two-factor-authentication","two-step-authentication"],"created_at":"2025-04-10T22:48:54.644Z","updated_at":"2025-10-14T02:04:33.813Z","avatar_url":"https://github.com/farshidbeheshti.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\" style=\"margin-bottom:0\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/8ef372d6-3cd7-4202-88b2-519f45f67160\" width=\"250\"  /\u003e\n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003eXOTP\u003c/h1\u003e\n\n[![Github Release](https://img.shields.io/github/v/release/farshidbeheshti/xotp)](https://www.npmjs.com/package/xotp)\n[![NPM Downloads](https://img.shields.io/npm/d18m/xotp)](https://www.npmjs.com/package/xotp)\n[![TypeScript](https://img.shields.io/badge/TypeScript-3178C9?logo=TypeScript\u0026logoColor=white)](https://github.com/farshidbeheshti/xotp)\n\n## Description\n\n`XOTP`(/zɔːtipi/) is a robust One-Time Password (HOTP/TOTP) library for Node.js, Bun, and Deno, written in TypeScript, with zero dependencies. It's Ideal for use in Two-Factor Authentication (2FA) / Multi-Factor Authentication (MFA) systems and is compatible with well-known authentication apps including Google Authenticator and Microsoft Authenticator.\n\nIt implements both [RFC 4226][rfc-4226] (HOTP) and [RFC 6238][rfc-6238] (TOTP), and has been fully tested with the test vectors from their respective RFC specifications: [RFC 4226 Dataset][rfc-4226-dataset] and [RFC 6238 Dataset][rfc-6238-dataset] in the `tests/data` folder.\n\nTry XOTP with the demo available at [xotp.dev][demo]!\n\n## Install\n\n```\nnpm i xotp\n```\n\n## Usage\n\n```js\nimport { Secret, TOTP } from \"xotp\";\n```\n\nAs a quick start, you could generate and verify OTPs in two easy steps:\n\n### Getting a Secret\n\nFirst, you need a secret key with which to generate a OTP.\nIf you already have a secret key as a string in any [supported encodings](#supported-encodings):\n\n```js\nconst secret = Secret.from(\"your Secret Key\");\n```\n\nOr use the `Secret` constructor function to generate a cryptographically strong 20-byte random key:\n\n```js\nconst secret = new Secret();\n```\n\nSee other [secret](#secret-reference) features if you need to generate the secret from a native Buffer type or store the secret in any encoding!\n\n### Generating a OTP token\n\nThen generate a OTP token with the secret you have just got:\n\n```js\nconst totp = new TOTP(/* options, if any! */);\nconst token = totp.generate({ secret });\n```\n\nYou can customize tokens using the optional argument of the `new TOTP()` constructor.\nTo know all options available for the `TOTP` constructor function and their defaults, see section [TOTP Options](#totp-options).\n\nHowever, you can aslo call the `generate({secret, ...options})` method with specific option values to use them instead of what you initialized the TOTP instance with.\n\n### OTP Verification\n\nThe user has submitted a token that you previously generated using XOTP or one of the authentication apps like Google Authenticator, and now you need to verify that:\n\n```js\nconst token = \"token submitted by user\"; // Token sent by user to validate against\nconst isValidToken = totp.validate({ secret, token });\n```\n\nLike almost all `TOTP` and `HOTP` methods, you can pass new option values to the `validate({secret, token, ...options})` method to use them instead of what you initialized the TOTP instance with.\n\n### Calculating Delta of Token\n\nIf you want to find the difference between the current time step and the time step in which a given token was generated, use the `compare` method:\n\n```js\nconst token = \"user token\";\nconst delta = totp.compare({ secret, token });\n```\n\nIt returns `0` if a token is for the current time step and `null` if the token is not found in the serach window, otherwise, returns the differences in window.\nYou could change search window in options passed to the method and also options passed to the TOTP constructor function, if you want to change the default value. Default value for the window is 1 and it means that it checks one time step before (-1) and also after (1) the current time step (0) to see if the token is generated in one of them.\n\n## Google Authenticator Key URI\n\n```js\nconst account = \"fullname, username or email\";\nconst keyUri = totp.keyUri({ secret, account });\n```\n\nThe `account` is the name of the user who otp is created for. It's used only to show the user in authenticator apps like google authenticator.\nAgain, you could use different values for options of ones you previously initialized a TOTP instance with.\n\n\u003e [!TIP]\n\u003e You may want to generate and display a QR Code of the generated `keyUri` above, so that could be scanned by authenticator apps like Google Authenticator and user does not have to manually enter the secret.\n\n\u003ca id=\"reference\"\u003e\u003ca\u003e\n\n## References\n\n### Secret\n\n\u003ca id=\"secret-reference\"\u003e\u003ca\u003e\n\nYou use `Secret` to generate and retrieve your secret keys in various encodings, so we're going to take a quick look at some of the its functions.\n\nUse the `Secret` constructor function to generate a secret key of desired size in bytes. It generates a cryptographically strong random key for you.\n\n```js\nconst secret = new Secret({ size: 64 });\n```\n\nThe size argument is a number indicating the number of bytes to generate, the default value is 20 bytes.\n\n```js\nconst secret = new Secret();\n// Same as\nconst secret = new Secret({ size: 20 });\n```\n\nIf you don't have idea of what size is right for your needs and only know the algorithm you're going to use, call the `for` static method to get an instance of the `Secret` for a specific algorithm of [supported variants](#supported-algorithms).\n\n```js\nconst secret = Secret.for(\"sha512\");\n```\n\n\u003e [!NOTE]\n\u003e XOTP uses `sha1` as the default algorithm for generating both `TOTP` and `HOTP` tokens. You could use the `sha1`, If you don't still know what algorithm you will use.\n\nIf you already have a secret key in binary, you could use a native `Buffer` object or javascript `ArrayBuffer` to initialize an instance of `Secret`, for example:\n\n```js\n// Just to define a dummy buffer of random 42-byte binary.\n// you would replace it with your buffer.\nconst buffer = Buffer.from(\n  Array.from({ length: 42 }, () =\u003e Math.round(Math.random())),\n);\n\nconst secret = new Secret({ buffer });\n```\n\nOr use the `from` static method to retrieve a `Secret` instance from the buffer:\n\n```js\nconst secret = Secret.from(buffer);\n```\n\nYou could also use `from` static method to get a `Secret` instance from a string in [different encodings](#supported-encodings).\n\n```js\nconst secret = Secret.from(\"LBHVIUBAFBKE6VCQF5EE6VCQFE======\", \"base32\");\n```\n\nAlmost all applications need to store the secret key to verify the user's token later. To do so, use `toString` method to get the string of the secret in one of the [available encodings](#supported-encodings):\n\n```js\nconst secretKey = secret.toString(\"hex\");\n```\n\nThe default encoding for `toString()` is `base32`, because almost all authenticator apps, including Google Authenticator, use `base32` as the default encoding for the secret key.\n\n\u003e [!NOTE]\n\u003e The default encoding for the `from` method is `utf-8` and the default encoding for `toString` is `base32`, so you need to pass the second argument in one of these two functions. That means:\n\u003e\n\u003e ```js\n\u003e const base32SecretKey = secret.toString();\n\u003e const clonedSecret = secret.from(base32SecretKey, \"base32\");\n\u003e ```\n\u003e\n\u003e Or vice versa:\n\u003e\n\u003e ```js\n\u003e const utf8SecretKey = secret.toString(\"utf-8\");\n\u003e const clonedSecret = secret.from(utf8SecretKey);\n\u003e ```\n\u003e\n\u003e We recommend the former!\n\n\u003ca id=\"totp_options\"\u003e\u003ca\u003e\n\n### TOTP Options\n\n| Option    | Type     | Default | Description                                                                                                                                                   |\n| --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| algorithm | `string` | \"sha1\"  | The algorithm used for calculating the HMAC, see [supported algorithms](#supported-algorithms)!                                                               |\n| digits    | `number` | 6       | The length of the OTP token.                                                                                                                                  |\n| window    | `number` | 1       | Number of window(s) within which validate the token. Try to validate token in the previous and future window if token is not validated in current time        |\n| duration  | `number` | 30      | duration (in seconds) a token is valid for.                                                                                                                   |\n| issuer    | `string` | \"xotp\"  | The provider or service with which the token is associated, e.g. Github. Used in the keyuri to show the user in authenticator apps like Google Authenticator. |\n| account   | `string` |         | The account with which the token is associated, e.g. the user's email. Used in the keyuri to show the user in authenticator apps like Google Authenticator.   |\n\n\u003e [!TIP]\n\u003e You can see that XOTP only gets options that are application-scoped and not user-specific ones, so you need only one instance of `TOTP` or `HOTP` class and reuse that throughout your application.\n\u003e This is also why XOTP does not allow the secret key to be included in the options, to avoid the terrible security problems of using a shared secret key.\n\n### HOTP\n\nXOTP also supports HOTP. Use \"HOTP\" instead of \"TOTP\" in all the examples above to see HOTP functions in action. Depending on your requirements, you may need to replace the `timestamp` argument with the `counter` if you are not using its functions with default arguments.\n\n\u003ca id=\"supported_encodings\"\u003e\u003ca\u003e\n\n### Supported Encodings:\n\n- `base32`\n- `base64`\n- `base64url`\n- `utf8` / `utf-8`\n- `utf16le` / `utf-16le` / `ucs2` / `ucs-2`\n- `latin1`\n- `ascii`\n- `binary`\n- `hex`\n\nIf you need an encoding that is not on this list, let us know via [issues][issues]!\n\n\u003e [!TIP]\n\u003e Google Authenticator uses `base32` encoding for the secret key!\n\n\u003ca id=\"supported_algorithms\"\u003e\u003ca\u003e\n\n### Supported Algorithms:\n\n- `sha1`\n- `sha224`\n- `sha256`\n- `sha512`\n- `sha384`\n- `sha-512/224`\n- `sha-512/256`\n- `sha3-224`\n- `sha3-256`\n- `sha3-384`\n- `sha3-512`\n\n  If you need an algorithm that is not in these options, please open an [issue][issues] for that!\n\n\u003e [!TIP]\n\u003e Google Authenticator ignores the algorithm type and uses `sha1` as the default.\n\n## License\n\n`XOTP` is [MIT licensed][project-license]\n\n\u003c!-- External Links --\u003e\n\n[rfc-3548]: http://tools.ietf.org/html/rfc3548\n[rfc-4226-dataset]: https://github.com/farshidbeheshti/xotp/blob/master/tests/data/rfc4226.ts\n[rfc-4226-wiki]: http://en.wikipedia.org/wiki/HMAC-based_One-time_Password_Algorithm\n[rfc-4226]: http://tools.ietf.org/html/rfc4226\n[rfc-4648]: https://tools.ietf.org/html/rfc4648\n[rfc-6238-dataset]: https://github.com/farshidbeheshti/xotp/blob/master/tests/data/rfc6238.ts\n[rfc-6238-wiki]: http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm\n[rfc-6238]: http://tools.ietf.org/html/rfc6238\n[project-license]: https://github.com/farshidbeheshti/xotp/blob/master/LICENSE\n[issues]: https://github.com/farshidbeheshti/xotp/issues\n[demo]: https://xotp.dev\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarshidbeheshti%2Fxotp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffarshidbeheshti%2Fxotp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarshidbeheshti%2Fxotp/lists"}