One-Time Token Plugin
Secure verification tokens for sensitive operations
The one-time token plugin generates secure, single-use verification codes for sensitive operations like account deletion, organization deletion, and other high-security actions.
Overview
This plugin provides cryptographically secure 6-digit verification codes that:
- Expire after 10 minutes
- Can only be used once
- Are stored as hashed values for security
- Use Web Crypto API for secure random generation
Use Cases
The one-time token plugin is used for:
- Account deletion verification
- Organization deletion verification
- Sensitive profile changes
- Any operation requiring email-based confirmation
Configuration
Default Settings
| Setting | Value | Description |
|---|---|---|
| Expiration | 10 minutes | Token validity period |
| Storage | Hashed | Tokens stored securely |
| Length | 6 digits | Code format (100000-999999) |
Implementation
Location
packages/better-auth/src/plugins/one-time-token.tsToken Generation
The plugin uses the Web Crypto API for cryptographically secure random number generation:
function generateSecureCode(): string { const array = new Uint32Array(1); crypto.getRandomValues(array); // Generate 6-digit code using rejection sampling // for uniform distribution const code = 100000 + (array[0] % 900000); return code.toString();}Plugin Configuration
import { oneTimeToken } from 'better-auth/plugins/one-time-token';const oneTimeTokenPlugin = oneTimeToken({ expiresIn: 10, // 10 minutes storeToken: 'hashed', // Store as hash generateToken: generateSecureCode,});Development Mode
In development (NODE_ENV=development), generated codes are logged to the console:
[DEV] Verification code: 847293This allows testing sensitive operations without checking email.
Usage Example
Delete Account Flow
// 1. Request verification code (sent via email)await authClient.oneTimeToken.sendToken({ type: 'account-delete',});// 2. User receives email with 6-digit code// 3. Verify code and complete actionawait authClient.oneTimeToken.verifyToken({ token: '847293', type: 'account-delete',});In the Application
The delete account dialog uses this flow:
// packages/account/ui/src/components/delete-account-dialog.tsx// Step 1: Send verification emailconst handleRequestCode = async () => { await sendVerificationEmail(); setStep('verify');};// Step 2: Verify code and deleteconst handleVerifyAndDelete = async (code: string) => { await verifyCodeAndDeleteAccount(code);};Security Features
Cryptographic Security
- Uses
crypto.getRandomValues()for true randomness - Rejection sampling ensures uniform distribution
- No predictable patterns in generated codes
Hashed Storage
Tokens are stored as hashed values in the database, preventing token theft even if the database is compromised.
Single Use
Each token can only be used once. After verification, the token is invalidated immediately.
Short Expiration
The 10-minute expiration window limits the attack surface for intercepted codes.
Error Handling
| Error | Description |
|---|---|
| Token expired | Code was not used within 10 minutes |
| Token invalid | Code doesn't match or was already used |
| Token not found | No pending verification for this operation |
Previous: Rate Limiting