--- status: "published" label: "OTP API" order: 5 title: "OTP API | Next.js Supabase SaaS Kit" description: "Generate and verify one-time passwords for secure operations in MakerKit. Use the OTP API for account deletion, ownership transfers, and other high-risk actions." --- The OTP API generates and verifies one-time passwords for secure operations like account deletion, ownership transfers, and email verification. It uses Supabase for secure token storage with automatic expiration and verification tracking. {% sequence title="How to use the OTP API" description="Learn how to use the OTP API in Makerkit" %} [OTP API - What is it for?](#otp-api---what-is-it-for) [Installation](#installation) [Basic Usage](#basic-usage) [Server Actions](#server-actions) [Verification UI Component](#verification-ui-component) [API Reference](#api-reference) [Database Schema](#database-schema) [Best Practices](#best-practices) [Example Use Cases](#example-use-cases) {% /sequence %} It is used for various destructive actions in the SaaS Kit, such as deleting accounts, deleting teams, and deleting users. However, you can use it for a variety of other purposes as well, such as: - Your custom destructive actions - oAuth account connections - etc. ## OTP API - What is it for? The OTP package offers: - **Secure Token Generation**: Create time-limited tokens with configurable expiration - **Email Delivery**: Send OTP codes via email with customizable templates - **Verification UI**: Ready-to-use verification form component - **Token Management**: Revoke, verify, and check token status ## Installation If you're using Makerkit, this package is already included. For manual installation: ```bash pnpm add @kit/otp ``` ## Basic Usage ### Creating and Sending an OTP To create and send an OTP, you can use the `createToken` method: ```typescript import { createOtpApi } from '@kit/otp/api'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; // Create the API instance const client = getSupabaseServerClient(); const api = createOtpApi(client); // Generate and send an OTP email await api.createToken({ userId: user.id, purpose: 'email-verification', expiresInSeconds: 3600, // 1 hour metadata: { redirectTo: '/verify-email' } }); // Send the email with the OTP await api.sendOtpEmail({ email: userEmail, otp: token.token }); ``` ### Verifying an OTP To verify an OTP, you can use the `verifyToken` method: ```typescript // Verify the token const result = await api.verifyToken({ token: submittedToken, purpose: 'email-verification' }); if (result.valid) { // Token is valid, proceed with the operation const { userId, metadata } = result; // Handle successful verification } else { // Token is invalid or expired // Handle verification failure } ``` ## Server Actions The package includes a ready-to-use server action for sending OTP emails: ```typescript import { sendOtpEmailAction } from '@kit/otp/server/server-actions'; // In a form submission handler const result = await sendOtpEmailAction({ email: userEmail, purpose: 'password-reset', expiresInSeconds: 1800 // 30 minutes }); if (result.success) { // OTP was sent successfully } else { // Handle error } ``` **Note:** The `email` parameter is only used as verification mechanism, the actual email address being used is the one associated with the user. ## Verification UI Component The package includes a ready-to-use OTP verification form: ```tsx import { VerifyOtpForm } from '@kit/otp/components'; function MyVerificationPage() { return ( { // Handle successful verification // Use the OTP for verification on the server }} CancelButton={ } /> ); } ``` ## API Reference ### `createOtpApi(client)` Creates an instance of the OTP API. **Parameters**: - `client`: A Supabase client instance - **Returns**: OTP API instance with the following methods: ### `api.createToken(params)` Creates a new one-time token. **Parameters**: - `params.userId` (optional): User ID to associate with the token - `params.purpose`: Purpose of the token (e.g., 'password-reset') - `params.expiresInSeconds` (optional): Token expiration time in seconds (default: 3600) - `params.metadata` (optional): Additional data to store with the token - `params.description` (optional): Description of the token - `params.tags` (optional): Array of string tags - `params.scopes` (optional): Array of permission scopes - `params.revokePrevious` (optional): Whether to revoke previous tokens with the same purpose (default: true) **Returns**: ```typescript { id: string; // Database ID of the token token: string; // The actual token to send to the user expiresAt: string; // Expiration timestamp revokedPreviousCount: number; // Number of previously revoked tokens } ``` ### `api.verifyToken(params)` Verifies a one-time token. **Parameters**: - `params.token`: The token to verify - `params.purpose`: Purpose of the token (must match the purpose used when creating) - `params.userId` (optional): User ID for additional verification - `params.requiredScopes` (optional): Array of required permission scopes - `params.maxVerificationAttempts` (optional): Maximum allowed verification attempts **Returns**: ```typescript { valid: boolean; // Whether the token is valid userId?: string; // User ID associated with the token (if valid) metadata?: object; // Metadata associated with the token (if valid) message?: string; // Error message (if invalid) scopes?: string[]; // Permission scopes (if valid) purpose?: string; // Token purpose (if valid) } ``` ### `api.revokeToken(params)` Revokes a token to prevent its future use. **Parameters**: - `params.id`: ID of the token to revoke - `params.reason` (optional): Reason for revocation **Returns**: ```typescript { success: boolean; // Whether the token was successfully revoked } ``` ### `api.getTokenStatus(params)` Gets the status of a token. **Parameters**: - `params.id`: ID of the token **Returns**: ```typescript { exists: boolean; // Whether the token exists purpose?: string; // Token purpose userId?: string; // User ID associated with the token createdAt?: string; // Creation timestamp expiresAt?: string; // Expiration timestamp usedAt?: string; // When the token was used (if used) revoked?: boolean; // Whether the token is revoked revokedReason?: string; // Reason for revocation (if revoked) verificationAttempts?: number; // Number of verification attempts lastVerificationAt?: string; // Last verification attempt timestamp lastVerificationIp?: string; // IP address of last verification attempt isValid?: boolean; // Whether the token is still valid } ``` ### `api.sendOtpEmail(params)` Sends an email containing the OTP code. **Parameters**: - `params.email`: Email address to send to - `params.otp`: OTP code to include in the email **Returns**: Promise that resolves when the email is sent ## Database Schema The package uses a `nonces` table in your Supabase database with the following structure: - `id`: UUID primary key - `client_token`: Hashed token sent to client - `nonce`: Securely stored token hash - `user_id`: Optional reference to auth.users - `purpose`: Purpose identifier (e.g., 'password-reset') - Status fields: `expires_at`, `created_at`, `used_at`, etc. - Audit fields: `verification_attempts`, `last_verification_at`, etc. - Extensibility fields: `metadata`, `scopes` ## Best Practices 1. **Use Specific Purposes**: Always use descriptive, specific purpose identifiers for your tokens. 2. **Short Expiration Times**: Set token expiration times to the minimum necessary for your use case. 3. **Handle Verification Failures**: Provide clear error messages when verification fails. 4. **Secure Your Tokens**: Never log or expose tokens in client-side code or URLs. ## Example Use Cases - Email verification - Two-factor authentication - Account deletion confirmation - Important action verification Each use case should use a distinct purpose identifier. The purpose will always need to match the one used when creating the token. When you need to assign a specific data to a token, you can modify the purpose with a unique identifier, such as `email-verification-12345`. ## Related documentation - [Authentication API](/docs/next-supabase-turbo/api/authentication-api) - User authentication and session handling - [Team Account API](/docs/next-supabase-turbo/api/team-account-api) - Team management for ownership transfers - [Email Configuration](/docs/next-supabase-turbo/emails/email-configuration) - Configure email delivery for OTP codes - [Server Actions](/docs/next-supabase-turbo/data-fetching/server-actions) - Use OTP verification in server actions