Files
myeasycms-v2/docs/api/otp-api.mdoc
Giancarlo Buomprisco 7ebff31475 Next.js Supabase V3 (#463)
Version 3 of the kit:
- Radix UI replaced with Base UI (using the Shadcn UI patterns)
- next-intl replaces react-i18next
- enhanceAction deprecated; usage moved to next-safe-action
- main layout now wrapped with [locale] path segment
- Teams only mode
- Layout updates
- Zod v4
- Next.js 16.2
- Typescript 6
- All other dependencies updated
- Removed deprecated Edge CSRF
- Dynamic Github Action runner
2026-03-24 13:40:38 +08:00

302 lines
8.9 KiB
Plaintext

---
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 (
<VerifyOtpForm
purpose="password-reset"
email={userEmail}
onSuccess={(otp) => {
// Handle successful verification
// Use the OTP for verification on the server
}}
CancelButton={
<Button variant="outline" onClick={handleCancel}>
Cancel
</Button>
}
/>
);
}
```
## 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