In version 2.4.0, we've added support for OTP verification in Makerkit. This feature allows you to easily add two-factor authentication (2FA) to your application, providing an extra layer of security for sensitive operations.
While MFA was always possible to do thanks to Supabase Auth - we refer to OTP verification for different types of operations, such as:
- deleting a user's account, a team, or transferring ownership of a team
- super admin operations
- any other operation that requires extra security
OTP Verification in Makerkit
The package @kit/otp
provides a simple interface for managing OTP verification in your application.
We export three main parts from the package:
<VerifyOtpForm />
: A reusable form component for dispatching and verifying OTP codescreateOtpApi(client)
: An API for verifying OTP codes
The VerifyOtpForm
Component
The <VerifyOtpForm />
component is a reusable form component that handles the OTP verification process. It's designed to be used in conjunction with the createOtpApi
function, which we'll cover next.
Here's an example of how to use the component:
import { VerifyOtpForm } from '@kit/otp';import { useState } from 'react';const MyForm = () => { const [otp, setOtp] = useState(''); if (otp) { // render an action button that dispatches the OTP code return <FormActionConfirmation otp={otp} />; } return ( <VerifyOtpForm purpose="delete-account" onSubmit={setOtp} email="user@example.com" /> );};function FormActionConfirmation({ otp }) { return ( <button onClick={() => dispatchOtpAction(otp)}> Confirm Action </button> );}
The FormActionConfirmation
component is an example of how you might use the OTP code to dispatch an action. In this case, we're confirming the deletion of a user's account:
Now, let's call the createOtpApi
function to create an API for dispatching and verifying OTP codes:
'use server';import { createOtpApi } from '@kit/otp';import { getServerSupabaseClient } from '@kit/supabase/server-client';import { enhanceAction } from '@kit/next/actions';import { z } from 'zod';export const dispatchOtpAction = enhanceAction(async ({ user, data }) => { const supabase = getServerSupabaseClient(); const otpApi = createOtpApi(supabase); // retrieve the OTP code from the request const otpResult = await otpApi.verifyToken({ token: data.otp, userId: user.id, purpose: 'delete-personal-account', }); // token, userID and purpose must match // otherwise, the OTP code is invalid if (!otpResult.valid) { throw new Error('Invalid OTP'); } // OTP is valid, proceed with the operation}, { auth: true, schema: z.object({ otp: z.string().min(1), }),});
The above is a fairly simple example, but it demonstrates the basic idea.
- Dispatching an OTP code: The
VerifyOtpForm
component is used to render the OTP form, and will automatically handle sending an OTP code to the user's email address. - Verifying an OTP Code: The
createOtpApi
function takes a Supabase client instance. We then call theverifyToken
method on the API, passing in the OTP code and the user ID. The method returns a result object that indicates whether the OTP code is valid or not.
A few things to note:
- The
purpose
parameter is used to identify the type of operation being performed. This ensures that the OTP code is only valid for the intended purpose. - The
userId
parameter is used to associate the OTP code with a specific user. This ensures that the OTP code is only valid for the user who requested it.
If these parameters don't match, the OTP code is considered invalid, so it's important to ensure that they are correctly set.
Examples of OTP Verification: deleting a user's account
Deleting a user's account is a sensitive operation that requires extra security - therefore we made the decision to implement OTP verification for it.
The below video demonstrates how to delete a user's account using OTP verification:
Loading video...
Conclusion
OTP verification is a simple yet effective way to add extra security to your application. By implementing OTP verification for sensitive operations, you can ensure that your users' data is protected and their accounts are secure.
For more information about the OTP API, please refer to the OTP API documentation.