비트베이크

Integrating Custom SMS Auth in Next.js + Clerk in 5 Minutes via Webhook (Zero Paperwork)

2026-05-11T01:02:21.146Z

A professional, modern, and clean tech image featuring abstract digital lines and geometric shapes, suitable for developer authentication content with text overlay.

The Dilemma of SMS Authentication in Side Projects

If you are a Next.js developer building a side project or a startup MVP, you have likely chosen Clerk as your primary authentication solution. It is universally loved for its seamless integration of social logins and email magic links. However, when you decide to implement Phone Number Login (SMS OTP)—especially when targeting regions with strict telecom regulations like South Korea—you hit a massive roadblock.

Traditional SMS API providers demand an exhausting amount of paperwork before you can send a single text message:

  • Business Registration Certificates
  • Proof of Telecom Service Subscription
  • Mandatory Sender ID Pre-registration (which can take 1 to 3 business days to be approved)

As a solo developer or a freelance engineer, you just want to launch your MVP this weekend. You don't have the time or the business entity set up to deal with days of bureaucratic red tape. So, is there a way to integrate custom SMS authentication instantly, with zero paperwork?

The Solution: Clerk Custom Webhooks + EasyAuth

The answer is a resounding yes. You can build a robust, production-ready SMS authentication flow in under 5 minutes with absolutely no paperwork.

The secret lies in combining Clerk's Custom SMS Webhook feature with EasyAuth, a developer-centric SMS API designed for speed and simplicity.

In this architecture, Clerk handles the heavy lifting of user management, OTP code generation, and verification. It simply delegates the actual delivery of the SMS message to your Next.js server via a webhook. Your server then forwards this message to EasyAuth, which dispatches the SMS instantly.

Why EasyAuth is the Ultimate Developer Tool

  • Zero Paperwork: Forget about submitting business licenses or telecom proofs.
  • Instant Setup: Sign up, get your API key, and complete the API integration in 5 minutes.
  • Automated Sender ID: No need to pre-register and wait days for a sender number approval.
  • Highly Cost-Effective: At just 15~25 KRW per message, it is significantly cheaper than legacy providers (which charge 30~50 KRW). Plus, you get 10 free SMS upon signup to test your MVP immediately.

Step-by-Step Implementation Guide

Step 1. Configure the Webhook in the Clerk Dashboard

First, we need to instruct Clerk to notify our Next.js application whenever it generates an OTP that needs to be sent via SMS.

  1. Navigate to your Clerk Dashboard and open the [Webhooks] section.
  2. Click on Add Endpoint.
  3. Enter your Endpoint URL. If your Next.js app is running locally, use a tool like ngrok to expose your localhost (e.g., https://your-ngrok-url.app/api/webhooks/clerk-sms).
  4. Under 'Message Filtering', select the sms.created event.
  5. Once the webhook is created, copy the Signing Secret provided by Clerk. You will need to save this in your .env.local file.
CLERK_WEBHOOK_SECRET=whsec_your_clerk_secret
EASYAUTH_API_KEY=ea_your_easyauth_api_key

Step 2. Create the Next.js Webhook Route

We will be using the Next.js App Router. Create a new file at app/api/webhooks/clerk-sms/route.ts.

Security is paramount when dealing with webhooks. To ensure that the incoming requests are legitimately coming from Clerk and not a malicious actor, we will use the svix package to verify the webhook signatures.

npm install svix @clerk/nextjs

Step 3. Dispatch the SMS via EasyAuth API (Complete Code)

EasyAuth offers a beautifully simple two-endpoint API architecture:

  • POST /send - To dispatch an SMS.
  • POST /verify - To verify an OTP.

Because Clerk natively handles the verification of the OTP when using the webhook integration, we only need to utilize EasyAuth's POST /send endpoint.

Below is the complete, copy-pasteable code for your webhook route:

// app/api/webhooks/clerk-sms/route.ts
import { Webhook } from 'svix';
import { WebhookEvent } from '@clerk/nextjs/server';

export async function POST(req: Request) {
  const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET;
  
  if (!WEBHOOK_SECRET) {
    throw new Error('Please add CLERK_WEBHOOK_SECRET from Clerk Dashboard to .env or .env.local');
  }

  // 1. Extract Svix headers from the incoming request
  const svix_id = req.headers.get("svix-id");
  const svix_timestamp = req.headers.get("svix-timestamp");
  const svix_signature = req.headers.get("svix-signature");

  if (!svix_id || !svix_timestamp || !svix_signature) {
    return new Response('Error: Missing Svix headers', {
      status: 400
    });
  }

  // 2. Parse the request body and verify the signature
  const payload = await req.json();
  const body = JSON.stringify(payload);
  const wh = new Webhook(WEBHOOK_SECRET);

  let evt: WebhookEvent;

  try {
    evt = wh.verify(body, {
      "svix-id": svix_id,
      "svix-timestamp": svix_timestamp,
      "svix-signature": svix_signature,
    }) as WebhookEvent;
  } catch (err) {
    console.error('Error verifying webhook:', err);
    return new Response('Error verifying webhook signature', { status: 400 });
  }

  // 3. Process the sms.created event and trigger EasyAuth
  if (evt.type === 'sms.created') {
    const { phone_number, message } = evt.data;

    try {
      // Call EasyAuth's /send endpoint
      const easyAuthRes = await fetch('https://api.easyauth.co.kr/send', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.EASYAUTH_API_KEY}`
        },
        body: JSON.stringify({
          to: phone_number,
          text: message // This contains the OTP generated by Clerk
        })
      });

      if (!easyAuthRes.ok) {
        throw new Error('Failed to dispatch SMS via EasyAuth');
      }

      console.log(`SMS successfully dispatched to ${phone_number}`);
    } catch (error) {
      console.error('Failed to send SMS:', error);
      // Returning a 500 status will let Clerk know the delivery failed
      return new Response('Failed to deliver SMS', { status: 500 });
    }
  }

  // Acknowledge receipt of the webhook
  return new Response('Webhook processed successfully', { status: 200 });
}

Tips & Best Practices

  1. Never Skip Security Verification: Your webhook endpoint is public. If you skip the Svix signature verification, anyone who discovers your endpoint URL could exploit it to send SMS messages at your expense.
  2. Handle Errors Gracefully: Always wrap your external API calls in a try-catch block. If the EasyAuth API call fails (due to invalid phone numbers or unexpected network issues), returning a non-200 status code allows Clerk to mark the SMS delivery as failed in their dashboard.
  3. Fully Custom Auth Flows: If your project scales and you decide to migrate away from Clerk to build a 100% custom authentication system, you don't need to change your SMS provider. EasyAuth provides an equally simple POST /verify endpoint, allowing you to manage the entire generation, dispatch, and validation lifecycle internally with just a few lines of code.

Conclusion

By leveraging Clerk's Custom SMS Webhooks alongside EasyAuth, you can completely sidestep the bureaucratic nightmare of traditional telecom APIs.

As developers, our time is best spent writing business logic and shipping core features—not filling out business registration forms or waiting days for sender ID approvals. If you are a freelancer, a solo dev, or part of a startup team trying to move fast, EasyAuth is the perfect zero-paperwork solution designed explicitly for you.

Start immediately, launch your MVP in 5 minutes, and take advantage of the 10 free SMS credits available upon signup. Happy coding!

Start advertising on Bitbake

Contact Us

More Articles

2026-06-04T01:04:15.823Z

The 2026 E-Commerce New Product Launch Survival Formula: Dominating Platform Search Rankings in 7 Days via Reward-Based Trials and Purchase Verification

2026-06-04T01:04:15.800Z

2026 이커머스 신제품 론칭 생존 공식: 리워드형 체험단과 구매 인증으로 7일 만에 플랫폼 검색 랭킹 장악하기

2026-06-01T01:01:58.264Z

Surviving the 2026 Cookieless Era for B2C: Building Zero-Party Data with Reward-Based Quiz Marketing

2026-06-01T01:01:58.231Z

2026 쿠키리스 시대의 B2C 생존법: 리워드 기반 퀴즈 마케팅으로 제로파티 데이터 구축하기

Services

HomeFeedFAQCustomer Service

Inquiry

Bitbake

LAEM Studio | Business Registration No.: 542-40-01042

4th Floor, 402-J270, 16 Su-ro 116beon-gil, Wabu-eup, Namyangju-si, Gyeonggi-do

TwitterInstagramNaver Blog