Secure Authentication with Redis + Twilio : Rate Limiting OTP Generation in Spring Boot

The Java Trail
4 min readSep 7


“OTP” stands for “One-Time Password.” It is a security measure used to authenticate users and verify their identity during online transactions or account logins. A one-time password is a unique and temporary code that is typically valid for a short period of time, usually for a single login session or transaction. Since Redis has time-based expiration using the EXPIRE command, it is well-suited for building an OTP (One-Time Password) system. Redis can be used as an OTP (One-Time Password) generator in conjunction with other components to provide secure authentication for various applications.

OTP Generation with Redis:

  1. Speed and Efficiency: Redis’s in-memory nature makes it exceptionally fast in data retrieval and storage. .
  2. Key-Value Storage: Redis operates as a key-value store, where each OTP is associated with a unique key (e.g., user identifier or session ID). Storing OTPs in Redis ensures that they can be easily accessed, verified, and invalidated when needed.
  3. Time-Based Expiration: Redis allows setting a time-to-live (TTL) for keys, making it perfect for OTPs. OTPs can be stored with a TTL, ensuring they are automatically removed from Redis after a specified period, enhancing security by limiting their validity.
  4. Atomic Operations: Redis supports atomic operations like SETNX (set if not exists) and INCR (increment) which are invaluable for OTP generation and rate limiting.

Rate Limiting with Redis:

Rate limiting is a crucial mechanism for preventing abuse, brute force attacks, and ensuring fair resource utilization in applications. Redis can be effectively used for rate limiting:

  1. Key-Based Counting: Redis enables developers to maintain counters associated with specific keys (e.g., user IP addresses or session IDs). These counters can track the number of requests or actions within a given time frame.
  2. Expiration and Reset: Redis allows setting a TTL for these counters, acting as a sliding window. When the TTL expires, the counter is reset, and the user can perform actions again. This approach is more efficient than manual tracking.
  3. Efficient Rate Limiting Algorithms: Redis can be used to implement various rate limiting algorithms like token bucket or leaky bucket. These algorithms efficiently control the rate at which actions can be performed, providing a scalable solution.

Combining OTP Generation and Rate Limiting with Redis:

The synergy between OTP generation and rate limiting using Redis is particularly powerful. For instance, in user authentication, Redis can:

  • Generate OTPs on request, storing them with a TTL.
  • Use rate limiting to restrict the number of OTP generation attempts within a specified time frame, preventing abuse and protecting user accounts.
  • Store both the OTPs and rate-limiting information together, simplifying management and ensuring security.

SpringBoot Implementation

Step 1: Set Up Your Spring Boot Project

Create a new Spring Boot project with the necessary dependencies for Spring Web, Spring Data Redis, and Twilio. Use Spring Initializer or your IDE to set up the project.

<!-- Spring Data Redis -->

<!-- Twilio -->
<version>8.28.0</version> <!-- Use the latest Twilio version -->

Step 2: Configure Redis

Configure your Redis connection in the or application.yml:

Step 3: Add Twilio Configuration

Add your Twilio configuration in the


Step 4: Create Configuration Classes

Create a configuration class to load the Twilio configuration properties:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

public class TwilioConfig {

private String accountSid;

private String authToken;

private String phoneNumber;

public String getAccountSid() {
return accountSid;

public String getAuthToken() {
return authToken;

public String getPhoneNumber() {
return phoneNumber;

Step 5: Implement OTP Generation and Verification

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Random;

public class OTPService {

private StringRedisTemplate redisTemplate;

private TwilioService twilioService;

private static final String OTP_PREFIX = "otp:";
private static final String RATE_LIMIT_PREFIX = "rate_limit:";
private static final int RATE_LIMIT = 5;
private static final long RATE_LIMIT_PERIOD_SECONDS = 60;

public String generateOTP(String phoneNumber) {
// Check rate limiting
String rateLimitKey = RATE_LIMIT_PREFIX + phoneNumber;
if (!isRateLimited(rateLimitKey)) {
return "Rate limit exceeded. Please try again later.";

// Generate OTP
String otpKey = OTP_PREFIX + phoneNumber;
String existingOTP = redisTemplate.opsForValue().get(otpKey);
if (existingOTP != null) {
return "An OTP has already been generated for this number. Please check your SMS.";

String otpCode = generateRandomOTP(6);
redisTemplate.opsForValue().set(otpKey, otpCode, Duration.ofMinutes(5));

twilioService.sendOTP(phoneNumber, otpCode);

return "OTP generated and sent to " + phoneNumber;

public boolean verifyOTP(String phoneNumber, String otpCode) {
String otpKey = OTP_PREFIX + phoneNumber;
String storedOTP = redisTemplate.opsForValue().get(otpKey);

if (storedOTP != null && storedOTP.equals(otpCode)) {
return true;

return false;

private boolean isRateLimited(String rateLimitKey) {
Long currentCount = redisTemplate.opsForValue().increment(rateLimitKey, 1);
if (currentCount == 1) {
redisTemplate.expire(rateLimitKey, RATE_LIMIT_PERIOD_SECONDS, TimeUnit.SECONDS);
return currentCount <= RATE_LIMIT;

// Other methods as needed

Step 6: Implement TwilioService for OTP Delivery

Create a TwilioService to send OTPs via Twilio:

import com.twilio.Twilio;
import com.twilio.type.PhoneNumber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

public class TwilioService {

private final TwilioConfig twilioConfig;

public TwilioService(TwilioConfig twilioConfig) {
this.twilioConfig = twilioConfig;
Twilio.init(twilioConfig.getAccountSid(), twilioConfig.getAuthToken());

public void sendOTP(String phoneNumber, String otpCode) {
Message message = Message.creator(
new PhoneNumber(phoneNumber),
new PhoneNumber(twilioConfig.getPhoneNumber()),
"Your OTP is: " + otpCode)

Step 7: Create REST Endpoints

Create REST endpoints in a controller for OTP generation and verification:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

public class OTPController {

private OTPService otpService;

public ResponseEntity<String> generateOTP(@RequestParam String phoneNumber) {
String result = otpService.generateOTP(phoneNumber);
return ResponseEntity.ok(result);

public ResponseEntity<String> verifyOTP(@RequestParam String phoneNumber, @RequestParam String otpCode) {
boolean isValid = otpService.verifyOTP(phoneNumber, otpCode);
if (isValid) {
return ResponseEntity.ok("OTP verification successful");
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid OTP");

// Other endpoints as needed

Step 8: Run Your Spring Boot Application

Run your Spring Boot application. You can now use the /otp/generate and /otp/verify endpoints to generate and verify OTPs securely with rate limiting.



The Java Trail

Java Enthusiast, BackEnd Developer, TigerIT Bangladesh Ltd.