비트베이크

Building a Secure SMS OTP API in Express.js + TypeScript in 5 Minutes (Zero Paperwork & Rate Limited)

2026-05-26T01:02:06.691Z

A professional, clean, and modern image depicting developer authentication interfaces or abstract tech elements, suitable for a tech blog post thumbnail with text overlay.

Building a Secure SMS OTP API in Express.js + TypeScript in 5 Minutes (Zero Paperwork & Rate Limited)

😱 Blocked by SMS Authentication Paperwork?

If you're building a side project, an e-commerce platform, or a startup MVP, chances are you'll eventually need a phone verification (SMS OTP) feature for user registration or password recovery. However, when developers start looking for an SMS API provider, they are often hit with a frustrating reality:

  • Heavy Paperwork Requirements: Endless demands for business registration certificates, telecommunication carrier usage proofs, and other documents that indie hackers simply don't have.
  • Pre-registered Sender IDs: Even if you submit the paperwork, you face a tedious, multi-day review process just to register the phone number sending the SMS.
  • Prohibitive Costs: Expensive per-message pricing (often 30~50 KRW in the local market) that burns through a startup's limited budget.

For solo developers, freelancers, and early-stage startups trying to validate their ideas quickly, these barriers are incredibly discouraging. Isn't there a way to implement SMS verification immediately after signing up, completely free of paperwork?

In this comprehensive tutorial, we will learn how to build a highly secure SMS OTP API using Express.js and TypeScript. We'll be using EasyAuth, a developer-centric SMS API that requires absolutely zero paperwork and takes less than 5 minutes to integrate. We'll also cover crucial security implementations, specifically applying Rate Limiting to protect your API from malicious abuse, and how to manage OTP states without needing Redis.


💡 Why Choose EasyAuth?

Before diving into the code, let's briefly highlight why EasyAuth is the go-to solution for this implementation:

  1. Zero Paperwork: Simply sign up with your email and get your API Key instantly. No business licenses required.
  2. Automated Sender ID: Skip the manual review process; the system provisions and handles the sending numbers automatically.
  3. Affordable Pricing: Highly competitive rates at just 15~25 KRW per message—roughly half the traditional cost.
  4. Intuitive API Design: Forget complex setups. You only need two endpoints: POST /send and POST /verify.
  5. Free Trial: Receive 10 free SMS credits immediately upon signup to test your integration.

🛠️ Step 1: Project Setup and Dependencies

First, let's establish a solid server environment by setting up an Express.js and TypeScript project and installing the necessary packages.

# Initialize project
npm init -y

# Install core packages
# express: Web server framework
# axios: HTTP client for calling the EasyAuth API
# dotenv: Environment variable management
# express-rate-limit: Middleware to prevent excessive API requests
npm install express axios dotenv express-rate-limit

# Install TypeScript and type definitions for development
npm install -D typescript ts-node @types/express @types/node

# Generate tsconfig.json
npx tsc --init

Once installed, create a .env file in the root directory of your project and paste the API Key you generated from the EasyAuth dashboard.

PORT=3000
EASYAUTH_API_KEY=your_easyauth_api_key_here

🛡️ Step 2: Preventing Abuse with Rate Limiting

The most critical security vulnerability when exposing an SMS sending API is SMS Bombing. Because this endpoint is typically public (unauthenticated), malicious bots or users could theoretically call your /send endpoint thousands of times in a minute. This not only spams the victim but can also result in massive financial losses for you.

To mitigate this, we must configure an impregnable defense using the express-rate-limit package to block excessive requests originating from the same IP address within a specified timeframe.


🚀 Step 3: Complete Implementation Code

If you were using a traditional SMS API, you would have to generate a random 6-digit code on your backend, store it in a Redis cache or a database alongside its expiration time, and then send the message.

EasyAuth handles all of this internally. It generates the code, manages the state, and tracks expiration automatically. This stateless approach saves you from deploying and maintaining a Redis instance.

Here is the complete, production-ready server.ts code featuring both Rate Limiting and EasyAuth integration.

import express, { Request, Response } from 'express';
import rateLimit from 'express-rate-limit';
import axios from 'axios';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
app.use(express.json());

// ==========================================
// 1. Rate Limiting Setup (Prevent SMS Bombing)
// ==========================================
const otpLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes window
  max: 5, // Limit each IP to 5 requests per 15 minutes
  message: { 
    success: false, 
    error: 'Too many requests. Please try again later.' 
  },
  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  legacyHeaders: false, // Disable the `X-RateLimit-*` headers
});

// EasyAuth Configuration
const EASYAUTH_API_URL = 'https://api.easyauth.kr/v1';
const EASYAUTH_API_KEY = process.env.EASYAUTH_API_KEY;

// ==========================================
// 2. Send OTP API (/send)
// We apply the rate limiter strictly to the sending endpoint.
// ==========================================
app.post('/api/otp/send', otpLimiter, async (req: Request, res: Response) => {
  const { phone } = req.body;

  if (!phone) {
    return res.status(400).json({ success: false, error: 'Phone number is required.' });
  }

  try {
    // Call EasyAuth /send endpoint
    await axios.post(`${EASYAUTH_API_URL}/send`, 
      { phone }, 
      { headers: { Authorization: `Bearer ${EASYAUTH_API_KEY}` } }
    );
    
    res.status(200).json({ success: true, message: 'OTP sent successfully.' });
  } catch (error: any) {
    console.error('OTP Send Error:', error.response?.data || error.message);
    res.status(500).json({ success: false, error: 'Failed to send OTP.' });
  }
});

// ==========================================
// 3. Verify OTP API (/verify)
// ==========================================
app.post('/api/otp/verify', async (req: Request, res: Response) => {
  const { phone, code } = req.body;

  if (!phone || !code) {
    return res.status(400).json({ success: false, error: 'Phone number and code are required.' });
  }

  try {
    // Call EasyAuth /verify endpoint
    const response = await axios.post(`${EASYAUTH_API_URL}/verify`, 
      { phone, code }, 
      { headers: { Authorization: `Bearer ${EASYAUTH_API_KEY}` } }
    );

    // Handle verification response
    if (response.data.isValid) {
      res.status(200).json({ success: true, message: 'OTP verified successfully.' });
    } else {
      res.status(400).json({ success: false, error: 'Invalid or expired OTP code.' });
    }
  } catch (error: any) {
    console.error('OTP Verify Error:', error.response?.data || error.message);
    res.status(500).json({ success: false, error: 'Failed to verify OTP due to server error.' });
  }
});

// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`🚀 SMS OTP Server is running on port ${PORT}`);
});

Running the Code

You can easily run the development server via your terminal:

npx ts-node server.ts

💡 Essential Tips & Best Practices

  1. Rate Limiting is Mandatory, Not Optional As mentioned, because your OTP sending API is publicly accessible, you must limit the number of requests per IP using libraries like express-rate-limit. For higher-traffic applications, consider combining this with front-end protections like Google reCAPTCHA or Cloudflare turnstile.

  2. Strict Environment Variable Management Your API Key represents direct financial value. Never hardcode sensitive information into your source files. Always use a .env file and ensure it is firmly listed in your .gitignore before pushing to GitHub or any public repository.

  3. Embrace Stateless Architecture By letting EasyAuth manage the validity and expiration of the OTPs internally, your backend becomes wonderfully stateless. This means you don't need to spin up Redis instances or map out database tables just to keep track of generated codes. Calling /send and /verify is genuinely all it takes!


🎉 Conclusion

We've successfully designed and built a highly secure, rate-limited SMS OTP API using Express.js and TypeScript. As you can see from the code, implementing the actual business logic takes merely a few minutes.

As a developer, spending more time drowning in bureaucratic paperwork than writing actual code is a massive waste of your valuable resources. By adopting EasyAuth, you can eliminate these frustrations entirely.

  • 🚫 Zero Paperwork: Bypass the painful business registration and certificate hurdles.
  • Lightning Fast Setup: Sign up and complete your API integration in under 5 minutes.
  • 🤖 Automated Sender ID: Send messages immediately without tedious pre-registration processes.
  • 💰 Affordable Pricing: Highly competitive rates at just 15~25 KRW per message, keeping your overhead low.

Whether you're hacking together a weekend toy project, freelancing for a client, or pushing out a startup MVP, try EasyAuth today. Grab your 10 free test credits and implement SMS verification the modern, painless way!

비트베이크에서 광고를 시작해보세요

광고 문의하기

다른 글 보기

2026-08-06T06:01:33.120Z

2026 GTX 개통 임박! A/B/C 노선 수혜지역 투자 가이드

2026년 GTX A/B/C 노선 개통이 임박하며 수도권 부동산 시장이 들썩이고 있습니다. GTX 노선별 개통 현황과 함께, 주요 수혜지역을 심층 분석하고 실거주 및 투자를 위한 현명한 전략과 유의점을 제시하여 성공적인 아파트 투자를 돕는 가이드입니다.

2026-08-05T06:01:33.825Z

2026 하반기 재건축 투자: 규제 완화 속 핵심 전략

2026년 하반기, 규제 완화 기대감 속 재건축 투자의 핵심 전략을 알아봅니다. 정부 정책 변화 분석, 유망 지역 선정 기준, 주의할 점, 그리고 성공적인 투자를 위한 전문가들의 조언까지, 2026 부동산 시장에서 기회를 잡을 방법을 제시합니다.

2026-08-04T06:01:37.246Z

2026 하반기 청약, 대출 금리 변화 활용 내집마련 필승 전략

2026년 하반기 청약 시장은 변화하는 대출 금리와 정책, 지역별 수급 상황에 따라 기회와 도전이 공존합니다. 이 글에서는 부동산 시장 동향과 주택담보대출 전략, 인기 청약 단지 분석, 청약 가점 및 특별공급 활용 팁 등 내 집 마련을 위한 필승 전략을 제시합니다. 철저한 준비와 현명한 판단으로 2026년 내 집 마련의 꿈을 이루세요.

2026-08-04T01:01:36.795Z

2026년 청약 성공 전략: 무주택자 내집마련 필승 가이드

2026년 무주택자의 내집마련 꿈을 위한 필승 청약 전략 가이드입니다. 청약 가점부터 특별공급 활용법, 현명한 대출 전략, 유망 단지 분석, 그리고 제도 변화까지 2026년 청약 성공을 위한 모든 정보를 담았습니다.

서비스

피드자주 묻는 질문고객센터

문의

비트베이크

레임스튜디오 | 사업자 등록번호 : 542-40-01042

경기도 남양주시 와부읍 수례로 116번길 16, 4층 402-제이270호

트위터인스타그램네이버 블로그