### Install Speakeasy.js with npm Source: https://github.com/speakeasyjs/speakeasy/wiki/Home This command installs the Speakeasy.js library as a project dependency using npm. It is typically run once during project setup. ```shell npm install --save speakeasy ``` -------------------------------- ### TOTP Token Generation and Verification Examples (JavaScript) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Illustrates generating TOTP tokens at specific times and verifying them using `verifyDelta` and `verify` with a defined window. Demonstrates how the two-sided window works for TOTP, allowing for negative deltas. Requires a secret, time, and window size. ```javascript var secret = 'rNONHRni6BAk7y2TiKrv'; // By way of example, we will force TOTP to return tokens at time 1453853945 and // at time 1453854005 (60 seconds ahead, or 2 steps ahead) var token1 = speakeasy.totp({ secret: secret, time: 1453853945 }); // 625175 var token3 = speakeasy.totp({ secret: secret, time: 1453854005 }); // 222636 var token2 = speakeasy.totp({ secret: secret, time: 1453854065 }); // 013052 // We can check the time at token 3, 1453854005, with token 1, but use a window of 2 // With a time step of 30 seconds, this will check all tokens from 60 seconds // before the time to 60 seconds after the time speakeasy.totp.verifyDelta({ secret: secret, token: token1, window: 2, time: 1453854005 }); // => { delta: -2 } // token is valid because because token is 60 seconds before time speakeasy.totp.verify({ secret: secret, token: token1, window: 2, time: 1453854005 }); // => true // token is valid because because token is 0 seconds before time speakeasy.totp.verify({ secret: secret, token: token3, window: 2, time: 1453854005 }); // => true // token is valid because because token is 60 seconds after time speakeasy.totp.verify({ secret: secret, token: token2, window: 2, time: 1453854005 }); // => true // This signifies that the given token, token1, is -2 steps away from // the given time, which means that it is the token for the value at // (-2 * time step) = (-2 * 30 seconds) = 60 seconds ago. ``` -------------------------------- ### Generate QR Code Data URL with Node.js Source: https://github.com/speakeasyjs/speakeasy/wiki/Display-QR-Code This snippet demonstrates how to generate a PNG data URL for a QR code using the `node-qrcode` package. The data URL can be directly used in an `` tag for web display. It requires the `qrcode` package to be installed (`npm install --save node-qrcode`). ```javascript var QRCode = require('qrcode'); // Assuming 'secret' is an object with an 'otpauth_url' property from Speakeasy QRCode.toDataURL(secret.otpauth_url, function(err, data_url) { if (err) { console.error(err); return; } console.log(data_url); // Example of how to use it in HTML: // write(''); }); ``` -------------------------------- ### HOTP Token Generation and Verification Examples (JavaScript) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Demonstrates generating HOTP tokens for specific counters and verifying them using `verifyDelta` and `verify` with a defined window. Highlights how the window affects verification results, including cases where tokens are within or outside the window. Requires a secret and counter. ```javascript // Set ASCII secret var secret = 'rNONHRni6BAk7y2TiKrv'; // Get HOTP counter token at counter = 42 var counter42 = speakeasy.hotp({ secret: secret, counter: 42 }); // => '566646' // Get HOTP counter token at counter = 45 var counter45 = speakeasy.hotp({ secret: secret, counter: 45 }); // => '323238' // Verify the secret at counter 42 with the actual value and a window of 10 // This will check all counter values from 42 to 52, inclusive speakeasy.hotp.verifyDelta({ secret: secret, counter: 42, token: counter42, window: 10 }); // => { delta: 0 } because the given token at counter 42 is 0 steps away from the given counter 42 // Verify the secret at counter 45, but give a counter of 42 and a window of 10 // This will check all counter values from 42 to 52, inclusive speakeasy.hotp.verifyDelta({ secret: secret, counter: 42, token: counter45, window: 10 }); // => { delta: 3 } because the given token at counter 45 is 0 steps away from given counter 42 // Not in window: specify a window of 1, which only tests counters 42 and 43, not 45 speakeasy.hotp.verifyDelta({ secret: secret, counter: 42, token: counter45, window: 1 }); // => undefined // Shortcut to use verify() to simply return whether it is verified as within the window speakeasy.hotp.verify({ secret: secret, counter: 42, token: counter45, window: 10 }); // => true // Not in window: specify a window of 1, which only tests counters 42 and 43, not 45 speakeasy.hotp.verify({ secret: secret, counter: 42, token: counter45, window: 1 }); // => false ``` -------------------------------- ### Generate a Secret Key for Two-Factor Authentication Source: https://github.com/speakeasyjs/speakeasy/wiki/Home This JavaScript code snippet demonstrates how to generate a secret key using the Speakeasy library. The generated secret includes ASCII, hexadecimal, and base32 encodings, as well as an OTPAuth URL for QR code generation. This secret is crucial for setting up two-factor authentication. ```javascript var secret = speakeasy.generateSecret(); // Returns an object with secret.ascii, secret.hex, and secret.base32. // Also returns secret.otpauth_url, which we'll use later. ``` -------------------------------- ### Display QR Code for Authenticator App Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Generates a QR code that can be scanned by authenticator apps like Google Authenticator. It uses the 'qrcode' package to convert the 'otpauth_url' from the generated secret into a data URL, which can be displayed as an image. Ensure the 'qrcode' package is installed (`npm install --save qrcode`). ```javascript var QRCode = require('qrcode'); // Assuming 'secret' is the object generated by speakeasy.generateSecret() QRCode.toDataURL(secret.otpauth_url, function(err, data_url) { console.log(data_url); // Display this data URL to the user in an tag // Example: // write(''); }); ``` -------------------------------- ### Generate otpauth:// URL with Custom Algorithm (JavaScript) Source: https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Time-Based-Token Generates an `otpauth://` URL suitable for QR code generation and integration with authenticator apps. This example specifically shows how to create a URL using the SHA512 algorithm, along with custom labels and secret keys. ```javascript var speakeasy = require("speakeasy"); // Generate a secret, if needed var secret = speakeasy.generateSecret(); // By default, generateSecret() returns an otpauth_url for totp, SHA1 and // 'SecretKey' label // otpauth://totp/SecretKey?secret= // Use otpauthURL() to get a custom authentication URL for SHA512 var url = speakeasy.otpauthURL({ secret: secret.ascii, label: 'Name of Secret', algorithm: 'sha512' }); // otpauth://totp/Name%20of%20Secret?secret=&algorithm=SHA512 // Use otpauthURL() to get a custom authentication URL for SHA512, issuer // and digits var url = speakeasy.otpauthURL({ secret: secret.base32, label: 'Name of Secret', algorithm: 'sha512', issuer:'Company', digits: 6, encoding: 'base32' }); // otpauth://totp/Name%20of%20Secret?secret=&issuer=Company&algorithm=SHA512&digits=6 // Pass URL into a QR code generator ``` -------------------------------- ### Node.js Production-Ready 2FA Implementation Source: https://context7.com/speakeasyjs/speakeasy/llms.txt This Node.js code snippet demonstrates a complete two-factor authentication flow. It includes enabling 2FA by generating secrets and QR codes, verifying the initial setup token, and handling subsequent login verifications. It uses 'speakeasy' for OTP logic and 'qrcode' for generating QR codes. For production, replace the in-memory 'users' object with a persistent database. ```javascript const speakeasy = require('speakeasy'); const QRCode = require('qrcode'); const express = require('express'); const app = express(); // In-memory user store (use database in production) const users = {}; // Step 1: Enable 2FA - Generate secret app.post('/api/2fa/enable', async (req, res) => { const userId = req.body.userId; const userEmail = req.body.email; // Generate secret const secret = speakeasy.generateSecret({ name: userEmail, issuer: 'MyApp', length: 32 }); // Store temporary secret (don't enable 2FA yet) users[userId] = { email: userEmail, tempSecret: secret.base32, twoFactorEnabled: false }; // Generate QR code try { const qrCodeUrl = await QRCode.toDataURL(secret.otpauth_url); res.json({ secret: secret.base32, qrCode: qrCodeUrl, manualEntry: secret.base32 }); } catch (err) { res.status(500).json({ error: 'QR generation failed' }); } }); // Step 2: Verify first token and enable 2FA app.post('/api/2fa/verify-enable', (req, res) => { const userId = req.body.userId; const token = req.body.token; const user = users[userId]; if (!user || !user.tempSecret) { return res.status(400).json({ error: 'No pending 2FA setup' }); } // Verify the token const verified = speakeasy.totp.verify({ secret: user.tempSecret, encoding: 'base32', token: token, window: 2 }); if (verified) { // Move temp secret to permanent and enable 2FA user.twoFactorSecret = user.tempSecret; user.twoFactorEnabled = true; delete user.tempSecret; res.json({ success: true, message: '2FA enabled successfully' }); } else { res.status(401).json({ success: false, error: 'Invalid token' }); } }); // Step 3: Login verification app.post('/api/login/verify-2fa', (req, res) => { const userId = req.body.userId; const token = req.body.token; const user = users[userId]; if (!user || !user.twoFactorEnabled) { return res.status(400).json({ error: '2FA not enabled' }); } // Verify with delta tracking for logging const verification = speakeasy.totp.verifyDelta({ secret: user.twoFactorSecret, encoding: 'base32', token: token, window: 2 }); if (verification) { const driftSeconds = verification.delta * 30; console.log(`User ${userId} login: clock drift ${driftSeconds}s`); res.json({ success: true, message: 'Login successful', drift: driftSeconds }); } else { console.log(`Failed 2FA attempt for user ${userId}`); res.status(401).json({ success: false, error: 'Invalid token' }); } }); // Disable 2FA app.post('/api/2fa/disable', (req, res) => { const userId = req.body.userId; const token = req.body.token; const user = users[userId]; if (!user || !user.twoFactorEnabled) { return res.status(400).json({ error: '2FA not enabled' }); } // Verify current token before disabling const verified = speakeasy.totp.verify({ secret: user.twoFactorSecret, encoding: 'base32', token: token, window: 2 }); if (verified) { delete user.twoFactorSecret; user.twoFactorEnabled = false; res.json({ success: true, message: '2FA disabled' }); } else { res.status(401).json({ error: 'Invalid token' }); } }); app.listen(3000, () => console.log('Server running on port 3000')); ``` -------------------------------- ### TOTP Verification with Specific Time and Window in JavaScript Source: https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Time-Based-Token Demonstrates TOTP verification with a pre-defined secret, token, window, and a specific time. This example shows how `verifyDelta` returns the time step difference (delta) when a token is found within the specified window relative to the given time. It also illustrates how `verify` returns a boolean indicating if the token is valid within the window. ```javascript var secret = 'rNONHRni6BAk7y2TiKrv'; // By way of example, we will force TOTP to return tokens at time 1453853945 // and at time 1453854005 (60 seconds ahead, or 2 steps ahead) var token1 = speakeasy.totp({ secret: secret, time: 1453853945 }); // 625175 var token3 = speakeasy.totp({ secret: secret, time: 1453854005 }); // 222636 var token2 = speakeasy.totp({ secret: secret, time: 1453854065 }); // 013052 // We can check the time at token 3, 1453853975, with token 1, but use a window // of 2 With a time step of 30 seconds, this will check all tokens from 60 // seconds before the time to 60 seconds after the time speakeasy.totp.verifyDelta({ secret: secret, token: token1, window: 2, time: 1453854005 }); // => { delta: -2 } // token is valid because because token is 60 seconds before time speakeasy.totp.verify({ secret: secret, token: token1, window: 2, time: 1453854005 }); // => true // token is valid because because token is 0 seconds before time speakeasy.totp.verify({ secret: secret, token: token3, window: 2, time: 1453854005 }); // => true // token is valid because because token is 60 seconds after time speakeasy.totp.verify({ secret: secret, token: token2, window: 2, time: 1453854005 }); // This signifies that the given token, token1, is -2 steps away from // the given time, which means that it is the token for the value at // (-2 * time step) = (-2 * 30 seconds) = 60 seconds ago. ``` -------------------------------- ### Store Temporary Secret Key Source: https://github.com/speakeasyjs/speakeasy/wiki/Home This JavaScript code illustrates how to temporarily store the generated base32 encoded secret key. This is a placeholder for persisting the secret, which is necessary for authenticating a user's first token before it's permanently assigned. ```javascript // Example for storing the secret key somewhere (varies by implementation): user.two_factor_temp_secret = secret.base32; ``` -------------------------------- ### Verify HOTP Token with Window (JavaScript) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Verifies a HOTP token within a specified counter window. It checks a range of counter values starting from the provided counter. Returns the delta (difference in counter values) if found, or undefined if not within the window. Requires a secret, counter, token, and window size. ```javascript var token = speakeasy.hotp.verifyDelta({ secret: secret.ascii, counter: 42, token: '123456', window: 10 }); ``` -------------------------------- ### Verify TOTP Token with a Window in JavaScript Source: https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Time-Based-Token Verifies a TOTP token at the current time, checking tokens within a specified window. The function returns `{ delta: n }` where 'n' is the time step difference if found, or `undefined` if not found within the window. This example uses a window of 2, checking tokens from 60 seconds before to 60 seconds after the current time step. ```javascript var verified = speakeasy.totp.verifyDelta({ secret: secret.ascii, token: '123456', window: 2 }); ``` -------------------------------- ### Generate Time-Based Token with SHA256 Algorithm (JavaScript) Source: https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Time-Based-Token Demonstrates generating a time-based token using the SHA256 hashing algorithm. By default, speakeasy uses SHA1. This example shows how to specify a different algorithm for enhanced security. ```javascript var speakeasy = require("speakeasy"); // Assuming 'secret' is already generated // var secret = speakeasy.generateSecret({length: 20}); // Specifying SHA256 var token = speakeasy.totp({ secret: secret.ascii, algorithm: 'sha256' }); ``` -------------------------------- ### JavaScript HOTP Hardware Token System with Synchronization Source: https://context7.com/speakeasyjs/speakeasy/llms.txt Implements a hardware token system using HOTP with automatic counter synchronization and anti-desync features. This class simulates token issuance, code generation on a device, and verification with a wide window for resync. It handles failed attempts and includes an unlock mechanism. ```javascript const speakeasy = require('speakeasy'); class HardwareTokenSystem { constructor() { this.tokens = {}; // Store token state per user } // Initialize token for new user issueToken(userId) { const secret = speakeasy.generateSecret({ length: 20 }); this.tokens[userId] = { secret: secret.base32, serverCounter: 0, lastSuccessfulCounter: 0, failedAttempts: 0 }; return secret.base32; } // Generate token on hardware device (simulated) generateTokenOnDevice(userId) { const token = this.tokens[userId]; if (!token) throw new Error('Token not issued'); const code = speakeasy.hotp({ secret: token.secret, encoding: 'base32', counter: token.serverCounter }); // Simulate user pressing button - increment counter token.serverCounter++; return code; } // Verify token with automatic resync verifyToken(userId, userProvidedCode) { const token = this.tokens[userId]; if (!token) return { success: false, error: 'Token not found' }; // Check if account is locked due to too many failures if (token.failedAttempts >= 5) { return { success: false, error: 'Account locked' }; } // Attempt verification with delta tracking const result = speakeasy.hotp.verifyDelta({ secret: token.secret, encoding: 'base32', token: userProvidedCode, counter: token.lastSuccessfulCounter, window: 50 // Wide window for resync }); if (result) { // Successful verification const newCounter = token.lastSuccessfulCounter + result.delta + 1; const drift = result.delta; token.lastSuccessfulCounter = newCounter; token.failedAttempts = 0; console.log(`User ${userId}: Verified at counter ${newCounter}`); if (drift > 0) { console.log(`Resynced: user was ${drift} presses ahead`); } return { success: true, counter: newCounter, drift: drift, resynced: drift > 0 }; } else { // Failed verification token.failedAttempts++; console.log(`Failed attempt ${token.failedAttempts} for user ${userId}`); return { success: false, error: 'Invalid token', attemptsRemaining: 5 - token.failedAttempts }; } } // Reset failed attempts (admin function) unlockToken(userId) { if (this.tokens[userId]) { this.tokens[userId].failedAttempts = 0; return true; } return false; } // Get token status getTokenStatus(userId) { const token = this.tokens[userId]; if (!token) return null; return { counter: token.lastSuccessfulCounter, locked: token.failedAttempts >= 5, failedAttempts: token.failedAttempts }; } } // Usage example const system = new HardwareTokenSystem(); // Issue token to user const userId = 'user123'; const secret = system.issueToken(userId); console.log(`Token issued: ${secret}`); // Simulate user pressing button multiple times const code1 = system.generateTokenOnDevice(userId); const code2 = system.generateTokenOnDevice(userId); const code3 = system.generateTokenOnDevice(userId); // User logs in with code3 (skipped 2 codes) console.log(system.verifyToken(userId, code3)); // { success: true, counter: 3, drift: 2, resynced: true } // Next login with correct sequential code const code4 = system.generateTokenOnDevice(userId); console.log(system.verifyToken(userId, code4)); // { success: true, counter: 4, drift: 0, resynced: false } // Check status console.log(system.getTokenStatus(userId)); ``` -------------------------------- ### Require Speakeasy Library Source: https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Counter-Based-Token Imports the Speakeasy library for use in JavaScript projects. This is the initial step before utilizing any of its functionalities. ```javascript var speakeasy = require("speakeasy"); ``` -------------------------------- ### Verify HOTP Token with Counter Window in JavaScript Source: https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Counter-Based-Token This snippet demonstrates how to verify an HOTP token using a specified counter and a verification window. The `verifyDelta` function checks a range of counter values and returns the difference (delta) if the token is found within the window, or undefined otherwise. It requires the secret, the counter, the token to verify, and the window size. ```javascript var token = speakeasy.hotp.verifyDelta({ secret: secret.ascii, counter: 42, token: '123456', window: 10 }); ``` ```javascript // Set ASCII secret var secret = 'rNONHRni6BAk7y2TiKrv'; // Get HOTP counter token at counter = 42 var counter42 = speakeasy.hotp({ secret: secret, counter: 42 }); // => '566646' // Get HOTP counter token at counter = 45 var counter45 = speakeasy.hotp({ secret: secret, counter: 45 }); // => '323238' // Verify the secret at counter 42 with the actual value and a window of 10 // This will check all counter values from 42 to 52, inclusive speakeasy.hotp.verifyDelta({ secret: secret, counter: 42, token: counter42, window: 10 }); // => { delta: 0 } because the given token at counter 42 is 0 steps away from // the given counter 42 // Verify the secret at counter 45, but give a counter of 42 and a window of 10 // This will check all counter values from 42 to 52, inclusive speakeasy.hotp.verifyDelta({ secret: secret, counter: 42, token: counter45, window: 10 }); // => { delta: 3 } because the given token at counter 45 is 0 steps away from // given counter 42 // Not in window: specify a window of 1, which only tests counters 42 and 43, // not 45 speakeasy.hotp.verifyDelta({ secret: secret, counter: 42, token: counter45, window: 1 }); // => undefined ``` -------------------------------- ### generateSecret(options) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Generates a random secret key. ```APIDOC ## generateSecret(options) ### Description Generates a random secret with the set A-Z a-z 0-9 and symbols, of any length (default 32). ### Method N/A (Function Call) ### Endpoint N/A (Local Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **options** (Object) - Optional - - **length** (Integer) - Optional - The length of the secret. Defaults to 32. - **symbols** (Boolean) - Optional - Whether to include symbols in the secret. Defaults to false. - **encoding** (String) - Optional - The encoding of the secret (ascii, hex, base32, base64). Defaults to "base32". ### Request Example ```json { "length": 16, "symbols": true } ``` ### Response #### Success Response (Object | GeneratedSecret) - **Object | GeneratedSecret** - An object containing the generated secret and its URI. #### Response Example ```json { "ascii": "aBcDeFgHiJkLmNoP", "hex": "6142634465463431", "base32": "JBSWY3DPEHPK3PXP", "base64": "YWJjZGVmZ2hpamtsbW5v", "otpauth_url": "otpauth://totp/SecretKey?secret=JBSWY3DPEHPK3PXP" } ``` ``` -------------------------------- ### hotp.verifyDelta(options) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Verifies a counter-based one-time token (HOTP) and returns the delta. ```APIDOC ## hotp.verifyDelta(options) ### Description Verify a counter-based one-time token against the secret and return the delta. ### Method N/A (Function Call) ### Endpoint N/A (Local Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **options** (Object) - Required - - **secret** (String) - Required - Shared secret key - **token** (String) - Required - The one-time passcode to verify - **counter** (Integer) - Required - The current counter value - **digits** (Integer) - Optional - The number of digits for the one-time passcode. Defaults to 6. - **encoding** (String) - Optional - Key encoding (ascii, hex, base32, base64). Defaults to "ascii". - **algorithm** (String) - Optional - Hash algorithm (sha1, sha256, sha512). Defaults to "sha1". - **key** (String) - Optional - (DEPRECATED. Use `secret` instead.) Shared secret key ### Request Example ```json { "secret": "JBSWY3DPEHPK3PXP", "token": "123456", "counter": 1 } ``` ### Response #### Success Response (Object) - **Object** - An object containing the delta (difference between the provided token's counter and the calculated counter). Returns `null` if verification fails. #### Response Example ```json { "delta": 0 } ``` ``` -------------------------------- ### hotp(options) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Generates a counter-based one-time token (HOTP). ```APIDOC ## hotp(options) ### Description Generate a counter-based one-time token. Specify the key and counter, and receive the one-time password for that counter position as a string. You can also specify a token length, as well as the encoding (ASCII, hexadecimal, or base32) and the hashing algorithm to use (SHA1, SHA256, SHA512). ### Method N/A (Function Call) ### Endpoint N/A (Local Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **options** (Object) - Required - - **secret** (String) - Required - Shared secret key - **counter** (Integer) - Required - Counter value - **digest** (Buffer) - Optional - Digest, automatically generated by default - **digits** (Integer) - Optional - The number of digits for the one-time passcode. Defaults to 6. - **encoding** (String) - Optional - Key encoding (ascii, hex, base32, base64). Defaults to "ascii". - **algorithm** (String) - Optional - Hash algorithm (sha1, sha256, sha512). Defaults to "sha1". - **key** (String) - Optional - (DEPRECATED. Use `secret` instead.) Shared secret key - **length** (Integer) - Optional - (DEPRECATED. Use `digits` instead.) The number of digits for the one-time passcode. ### Request Example ```json { "secret": "JBSWY3DPEHPK3PXP", "counter": 1 } ``` ### Response #### Success Response (String) - **String** - The one-time passcode. #### Response Example ```json "123456" ``` ``` -------------------------------- ### HOTP Verify Delta API Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Verifies a counter-based one-time token against a secret and returns the delta. Allows for a window of leeway in verification. ```APIDOC ## POST /hotp/verifyDelta ### Description Verifies a counter-based one-time token against the secret and returns the delta. Allows for a window of leeway in verification. ### Method POST ### Endpoint /hotp/verifyDelta ### Parameters #### Request Body - **secret** (String) - Required - Shared secret key - **token** (String) - Required - Passcode to validate - **counter** (Integer) - Required - Counter value. This should be stored by the application and must be incremented for each request. - **digits** (Integer) - Optional - The number of digits for the one-time passcode. Defaults to 6. - **window** (Integer) - Optional - The allowable margin for the counter. Defaults to 0. - **encoding** (String) - Optional - Key encoding (ascii, hex, base32, base64). Defaults to "ascii". - **algorithm** (String) - Optional - Hash algorithm (sha1, sha256, sha512). Defaults to "sha1". ### Request Example ```json { "secret": "your_secret_key", "token": "123456", "counter": 100, "window": 5 } ``` ### Response #### Success Response (200) - **delta** (Integer) - The counter difference between the client and the server. ``` -------------------------------- ### HOTP Verification with Window Source: https://github.com/speakeasyjs/speakeasy/wiki/General-Usage-for-Counter-Based-Token Verify a HOTP token with a specified counter value and an inclusive window. This checks a range of counter values to find a match. ```APIDOC ## HOTP Verification with Window ### Description Verify a HOTP token with a specified counter value and an inclusive window. This checks a range of counter values to find a match. ### Method POST (simulated for documentation, actual function call) ### Endpoint /speakeasyjs/speakeasy/hotp/verifyDelta ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **secret** (string) - Required - The secret key used for generating the HOTP token. - **counter** (number) - Required - The base counter value to start checking from. - **token** (string) - Required - The HOTP token to verify. - **window** (number) - Required - The size of the window to check for the token. ### Request Example ```json { "secret": "rNONHRni6BAk7y2TiKrv", "counter": 42, "token": "123456", "window": 10 } ``` ### Response #### Success Response (200) - **delta** (number) - The difference between the verified counter and the base counter, if found within the window. #### Response Example ```json { "delta": 0 } ``` ### Error Handling - Returns `undefined` if the token is not found within the specified window. ``` -------------------------------- ### generateSecretASCII([length], [symbols]) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Generates a random ASCII secret key. ```APIDOC ## generateSecretASCII([length], [symbols]) ### Description Generates a key of a certain length (default 32) from A-Z, a-z, 0-9, and symbols (if requested). ### Method N/A (Function Call) ### Endpoint N/A (Local Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **length** (Integer) - Optional - The length of the secret. Defaults to 32. - **symbols** (Boolean) - Optional - Whether to include symbols in the secret. Defaults to false. ### Request Example ```json 16 ``` ### Response #### Success Response (String) - **String** - The generated ASCII secret. #### Response Example ```json "aBcDeFgHiJkLmNoP" ``` ``` -------------------------------- ### generateSecret Source: https://context7.com/speakeasyjs/speakeasy/llms.txt Generates a random secret key for two-factor authentication with multiple encoding formats and an optional Google Authenticator-compatible URL. ```APIDOC ## generateSecret(options) ### Description Generates a random secret key for two-factor authentication with multiple encoding formats and an optional Google Authenticator-compatible URL. ### Method `speakeasy.generateSecret(options)` ### Parameters #### Options - **length** (number) - Optional - The length of the secret key (default is 20). - **name** (string) - Optional - The name of the account for the `otpauth_url` (e.g., `user@example.com`). - **issuer** (string) - Optional - The issuer of the OTP (e.g., `MyApp`) for the `otpauth_url`. - **symbols** (boolean) - Optional - Whether to include symbols in the generated secret (default is true). - **encoding** (string) - Optional - The encoding format for the secret ('ascii', 'hex', 'base32', 'base64'). Defaults to 'ascii'. ### Request Example ```javascript const speakeasy = require('speakeasy'); // Basic secret generation const secret = speakeasy.generateSecret(); console.log(secret); // Generate secret with custom options const userSecret = speakeasy.generateSecret({ length: 20, name: 'user@example.com', issuer: 'MyApp', symbols: false }); console.log(userSecret.base32); console.log(userSecret.otpauth_url); ``` ### Response Returns an object containing the secret in various formats and an `otpauth_url`. #### Success Response - **ascii** (string) - The secret key encoded in ASCII. - **hex** (string) - The secret key encoded in hexadecimal. - **base32** (string) - The secret key encoded in Base32. - **otpauth_url** (string) - A URL compatible with Google Authenticator and other authenticator apps. #### Response Example ```json { "ascii": "rNONHRni6BAk7y2TiKrv2IJ4YJQ4FP+u", "hex": "724e4f4e48526e693642416b3779325469", "base32": "OJHD42KEIRLGSY2EICVTPESVCJKFSA", "otpauth_url": "otpauth://totp/SecretKey?secret=OJHD42KEIRLGSY2EICVTPESVCJKFSA" } ``` ``` -------------------------------- ### Generate Google Authenticator OTP Auth URL with SpeakeasyJS Source: https://context7.com/speakeasyjs/speakeasy/llms.txt Generates Google Authenticator-compatible otpauth:// URLs for provisioning mobile authenticator apps. Supports TOTP and HOTP, with options for issuer, algorithm, digits, and period. Requires the 'speakeasy' package. ```javascript const speakeasy = require('speakeasy'); // Basic TOTP URL generation const url = speakeasy.otpauthURL({ secret: 'JBSWY3DPEHPK3PXP', label: 'user@example.com' }); console.log(url); // 'otpauth://totp/user@example.com?secret=JBSWY3DPEHPK3PXP' // Complete URL with issuer and algorithm const fullUrl = speakeasy.otpauthURL({ secret: 'JBSWY3DPEHPK3PXP', label: 'user@example.com', issuer: 'MyApp', algorithm: 'sha256', digits: 8, period: 60 }); console.log(fullUrl); // 'otpauth://totp/user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=MyApp&algorithm=SHA256&digits=8&period=60' // HOTP URL generation (counter-based) const hotpUrl = speakeasy.otpauthURL({ secret: 'JBSWY3DPEHPK3PXP', label: 'Hardware Token', type: 'hotp', counter: 0, issuer: 'SecureBank' }); console.log(hotpUrl); // 'otpauth://hotp/Hardware%20Token?secret=JBSWY3DPEHPK3PXP&issuer=SecureBank&counter=0' // Complete two-factor setup with QR code const QRCode = require('qrcode'); // npm install qrcode function setupTwoFactor(userId, userEmail) { // Generate secret const secret = speakeasy.generateSecret({ name: userEmail, issuer: 'MyApp' }); // Create otpauth URL const otpauthUrl = speakeasy.otpauthURL({ secret: secret.ascii, label: userEmail, issuer: 'MyApp', encoding: 'ascii' }); // Generate QR code QRCode.toDataURL(otpauthUrl, (err, dataUrl) => { if (err) { console.error('QR code generation failed:', err); return; } console.log('Setup information:'); console.log('Secret (base32):', secret.base32); console.log('QR Code Data URL:', dataUrl); console.log('Manual entry code:', secret.base32); // Store secret.base32 in database for userId // Display dataUrl as to user }); } setupTwoFactor('user123', 'john@example.com'); // Convert existing secret to URL for re-display const existingSecret = 'JBSWY3DPEHPK3PXP'; // From database const redisplayUrl = speakeasy.otpauthURL({ secret: existingSecret, label: 'user@example.com', issuer: 'MyApp', encoding: 'base32' }); // Generate QR code from this URL for backup/re-setup ``` -------------------------------- ### digest(options) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Digests the one-time passcode options to generate a Buffer. ```APIDOC ## digest(options) ### Description Digest the one-time passcode options. ### Method N/A (Function Call) ### Endpoint N/A (Local Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **options** (Object) - Required - - **secret** (String) - Required - Shared secret key - **counter** (Integer) - Required - Counter value - **encoding** (String) - Optional - Key encoding (ascii, hex, base32, base64). Defaults to "ascii". - **algorithm** (String) - Optional - Hash algorithm (sha1, sha256, sha512). Defaults to "sha1". - **key** (String) - Optional - (DEPRECATED. Use `secret` instead.) Shared secret key ### Request Example ```json { "secret": "JBSWY3DPEHPK3PXP", "counter": 1 } ``` ### Response #### Success Response (Buffer) - **Buffer** - The one-time passcode as a buffer. #### Response Example ```json ``` ``` -------------------------------- ### otpauthURL(options) Source: https://github.com/speakeasyjs/speakeasy/blob/master/README.md Generates an OTPAuth URL for authenticator apps. ```APIDOC ## otpauthURL(options) ### Description Generate an URL for use with the Google Authenticator app. ### Method N/A (Function Call) ### Endpoint N/A (Local Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **options** (Object) - Required - - **secret** (String) - Required - Shared secret key - **label** (String) - Required - Account name (e.g., "user@example.com") - **issuer** (String) - Optional - Service name (e.g., "My Service") - **encoding** (String) - Optional - Key encoding (ascii, hex, base32, base64). Defaults to "base32". ### Request Example ```json { "secret": "JBSWY3DPEHPK3PXP", "label": "test@example.com", "issuer": "My App" } ``` ### Response #### Success Response (String) - **String** - The OTPAuth URL. #### Response Example ```json "otpauth://totp/My%20App:test@example.com?secret=JBSWY3DPEHPK3PXP&issuer=My%20App" ``` ``` -------------------------------- ### Verify HOTP Token with Speakeasyjs Source: https://context7.com/speakeasyjs/speakeasy/llms.txt Verifies a counter-based HOTP token against a secret. Supports a look-ahead window to manage counter synchronization issues, ensuring token validity even with slight delays or resynchronization attempts. Requires the secret, encoding type, the user-provided token, and the current counter value. ```javascript const speakeasy = require('speakeasy'); // Basic counter verification const secret = 'JBSWY3DPEHPK3PXP'; const userToken = '123456'; const counter = 42; const verified = speakeasy.hotp.verify({ secret: secret, encoding: 'base32', token: userToken, counter: counter }); console.log(verified); // true or false // Verification with window (handles counter desync) const verifiedWithWindow = speakeasy.hotp.verify({ secret: secret, encoding: 'base32', token: userToken, counter: 42, window: 10 // Check counters 42-52 }); console.log(verifiedWithWindow); // true if token matches any counter in range // Complete hardware token verification class TokenVerifier { constructor(secret) { this.secret = secret; this.currentCounter = 0; } verify(userToken) { const verified = speakeasy.hotp.verify({ secret: this.secret, encoding: 'base32', token: userToken, counter: this.currentCounter, window: 5 // Allow up to 5 button presses ahead }); if (verified) { this.currentCounter++; console.log('Token verified, counter incremented'); return true; } console.log('Token invalid'); return false; } } const verifier = new TokenVerifier('JBSWY3DPEHPK3PXP'); console.log(verifier.verify('123456')); // Production example with counter persistence function verifyHOTPToken(userId, userSecret, userToken, storedCounter) { const verified = speakeasy.hotp.verify({ secret: userSecret, encoding: 'base32', token: userToken, counter: storedCounter, window: 10 }); if (verified) { const newCounter = storedCounter + 1; // saveCounterToDatabase(userId, newCounter); console.log(`Verified. New counter: ${newCounter}`); return { success: true, newCounter }; } return { success: false, newCounter: storedCounter }; } ```