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
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 address to send confirmation to. Required for email-based confirmations.
Phone number to send SMS to. Required for SMS confirmations.
URL to redirect to after confirmation (for email links).
Captcha token for verification if captcha is enabled.
Response
Unique identifier for the sent message (when available)
{
"message_id" : "msg_1234567890abcdef"
}
Error Responses
400 - Missing Required Field
404 - User Not Found
429 - Rate Limited
{
"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"
}
Magic Link
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:
Type Limit Window Email confirmations 3 per email 5 minutes SMS confirmations 2 per phone 5 minutes General 10 per IP 10 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
Email not received
Check spam/junk folders
Verify email address is correct
Check email provider restrictions
SMS not received
Verify phone number format
Check carrier restrictions
Ensure phone has signal
Rate limit errors
Wait for rate limit window to reset
Implement proper retry logic
Consider using exponential backoff