Skip to main content
POST
/
resend
curl -X POST "http://localhost:8080/resend" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "signup",
    "email": "user@example.com"
  }'
{
  "message_id": "msg_1234567890abcdef"
}
Resend confirmation email or SMS to users who haven’t received or lost their verification messages. This endpoint helps users complete the verification process when the original message is missing.
This endpoint does not require authentication and can be called by anyone with a valid email or phone number.
curl -X POST "http://localhost:8080/resend" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "signup",
    "email": "user@example.com"
  }'

Request Body

type
string
required
The type of confirmation to resend.Options:
  • signup - Email/phone confirmation after registration
  • recovery - Password recovery email
  • magiclink - Magic link for passwordless login
  • email_change - Email change confirmation
  • sms - SMS verification code
email
string
Email address to send confirmation to. Required for email-based confirmations.
phone
string
Phone number to send SMS to. Required for SMS confirmations.
redirect_to
string
URL to redirect to after confirmation (for email links).
captcha_token
string
Captcha token for verification if captcha is enabled.

Response

message_id
string
Unique identifier for the sent message (when available)
{
  "message_id": "msg_1234567890abcdef"
}

Error Responses

{
  "code": 400,
  "msg": "Missing required field",
  "details": "Email is required for email confirmations"
}

Resend Types

Email Signup Confirmation

Resend email verification for user registration:
{
  "type": "signup",
  "email": "user@example.com",
  "redirect_to": "https://yourapp.com/verified"
}

SMS Verification Code

Resend SMS verification code:
{
  "type": "sms",
  "phone": "+1234567890"
}

Password Recovery Email

Resend password recovery email:
{
  "type": "recovery",
  "email": "user@example.com",
  "redirect_to": "https://yourapp.com/reset-password"
}
Resend magic link for passwordless login:
{
  "type": "magiclink",
  "email": "user@example.com",
  "redirect_to": "https://yourapp.com/dashboard"
}

Email Change Confirmation

Resend email change confirmation:
{
  "type": "email_change",
  "email": "newemail@example.com"
}

Implementation Examples

React Resend Component

import { useState } from 'react';

function ResendConfirmation({ type, email, phone, onSuccess, onError }) {
  const [loading, setLoading] = useState(false);
  const [sent, setSent] = useState(false);

  const handleResend = async () => {
    setLoading(true);
    
    try {
      const requestBody = { type };
      
      if (email) requestBody.email = email;
      if (phone) requestBody.phone = phone;
      
      const response = await fetch('/api/auth/resend', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(requestBody),
      });

      if (!response.ok) {
        const error = await response.json();
        throw new Error(error.msg || 'Failed to resend confirmation');
      }

      const result = await response.json();
      setSent(true);
      onSuccess?.(result);
      
    } catch (error) {
      onError?.(error.message);
    } finally {
      setLoading(false);
    }
  };

  if (sent) {
    return (
      <div className="success-message">
        <p>✅ Confirmation sent successfully!</p>
        <p>Please check your {type === 'sms' ? 'phone' : 'email'} for the verification message.</p>
      </div>
    );
  }

  return (
    <div className="resend-confirmation">
      <p>Didn't receive the confirmation {type === 'sms' ? 'code' : 'email'}?</p>
      <button 
        onClick={handleResend} 
        disabled={loading}
        className="resend-button"
      >
        {loading ? 'Sending...' : 'Resend Confirmation'}
      </button>
    </div>
  );
}

export default ResendConfirmation;

Node.js Backend Handler

const express = require('express');
const router = express.Router();

router.post('/resend', async (req, res) => {
  try {
    const { type, email, phone, redirect_to, captcha_token } = req.body;

    // Validate required fields
    if (!type) {
      return res.status(400).json({
        code: 400,
        msg: 'Missing required field',
        details: 'Type is required'
      });
    }

    // Validate email/phone based on type
    if (['signup', 'recovery', 'magiclink', 'email_change'].includes(type) && !email) {
      return res.status(400).json({
        code: 400,
        msg: 'Missing required field',
        details: 'Email is required for this confirmation type'
      });
    }

    if (type === 'sms' && !phone) {
      return res.status(400).json({
        code: 400,
        msg: 'Missing required field',
        details: 'Phone number is required for SMS confirmations'
      });
    }

    // Call Strike Auth Service
    const response = await fetch(`${process.env.AUTH_SERVICE_URL}/resend`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(req.body),
    });

    const data = await response.json();

    if (!response.ok) {
      return res.status(response.status).json(data);
    }

    // Log successful resend
    console.log(`Confirmation resent: ${email || phone}, type: ${type}`);

    res.json(data);

  } catch (error) {
    console.error('Resend error:', error);
    res.status(500).json({
      code: 500,
      msg: 'Internal server error',
      details: 'Please try again later'
    });
  }
});

module.exports = router;

Rate Limiting

This endpoint is rate limited to prevent spam:
TypeLimitWindow
Email confirmations3 per email5 minutes
SMS confirmations2 per phone5 minutes
General10 per IP10 minutes

Security Considerations

  • Rate Limiting: Prevents spam and abuse
  • User Validation: Only sends to existing users
  • Captcha Support: Optional captcha verification
  • No Information Disclosure: Doesn’t reveal if email/phone exists

Best Practices

  • Provide clear feedback when confirmation is sent
  • Show countdown timer before allowing resend
  • Offer alternative contact methods if available
  • Include troubleshooting tips for common issues
  • Implement proper rate limiting
  • Use captcha for high-risk scenarios
  • Log resend attempts for monitoring
  • Don’t reveal user existence in error messages
  • Use reputable email service providers
  • Implement proper SPF, DKIM, and DMARC records
  • Monitor delivery rates and bounce rates
  • Provide clear sender information
  • Use reliable SMS providers
  • Include clear sender identification
  • Respect opt-out requests
  • Monitor delivery rates and costs

Testing

Unit Tests

describe('POST /resend', () => {
  test('should resend email confirmation', async () => {
    const response = await request(app)
      .post('/resend')
      .send({
        type: 'signup',
        email: 'test@example.com'
      })
      .expect(200);

    expect(response.body.message_id).toBeDefined();
  });

  test('should resend SMS confirmation', async () => {
    const response = await request(app)
      .post('/resend')
      .send({
        type: 'sms',
        phone: '+1234567890'
      })
      .expect(200);

    expect(response.body.message_id).toBeDefined();
  });

  test('should reject missing email for email type', async () => {
    await request(app)
      .post('/resend')
      .send({
        type: 'signup'
      })
      .expect(400);
  });

  test('should respect rate limits', async () => {
    // Send multiple requests quickly
    for (let i = 0; i < 5; i++) {
      await request(app)
        .post('/resend')
        .send({
          type: 'signup',
          email: 'test@example.com'
        });
    }

    // Should be rate limited
    await request(app)
      .post('/resend')
      .send({
        type: 'signup',
        email: 'test@example.com'
      })
      .expect(429);
  });
});

Troubleshooting

Common Issues

  1. Email not received
    • Check spam/junk folders
    • Verify email address is correct
    • Check email provider restrictions
  2. SMS not received
    • Verify phone number format
    • Check carrier restrictions
    • Ensure phone has signal
  3. Rate limit errors
    • Wait for rate limit window to reset
    • Implement proper retry logic
    • Consider using exponential backoff
I