To generate a unique token/OTP for each verification request and associate it with the user's email or session in Go, you can use a combination of cryptographic libraries and data structures. Here's an example implementation:
package main
import (
"crypto/rand"
"encoding/base64"
"fmt"
"sync"
"time"
)
// OTP struct represents an OTP with its associated email and expiration time
type OTP struct {
Email string
Token string
ExpiresAt time.Time
}
// OTPManager manages the generation and verification of OTPs
type OTPManager struct {
otps map[string]OTP
mu sync.Mutex
}
// NewOTPManager creates a new OTPManager instance
func NewOTPManager() *OTPManager {
return &OTPManager{
otps: make(map[string]OTP),
}
}
// GenerateOTP generates a unique OTP for the given email with a specified expiration time
func (m *OTPManager) GenerateOTP(email string, expiration time.Duration) (string, error) {
m.mu.Lock()
defer m.mu.Unlock()
// Generate a random token
tokenBytes := make([]byte, 32) // Adjust the length as per your requirements
_, err := rand.Read(tokenBytes)
if err != nil {
return "", fmt.Errorf("failed to generate OTP: %w", err)
}
token := base64.URLEncoding.EncodeToString(tokenBytes)
// Calculate the expiration time
expiresAt := time.Now().Add(expiration)
// Store the OTP in the manager
m.otps[email] = OTP{
Email: email,
Token: token,
ExpiresAt: expiresAt,
}
return token, nil
}
// VerifyOTP verifies the provided OTP for the given email
func (m *OTPManager) VerifyOTP(email, token string) bool {
m.mu.Lock()
defer m.mu.Unlock()
// Retrieve the stored OTP for the email
otp, ok := m.otps[email]
if !ok {
return false
}
// Check if the OTP is expired
if time.Now().After(otp.ExpiresAt) {
return false
}
// Compare the provided token with the stored OTP token
return otp.Token == token
}
func main() {
// Example usage
manager := NewOTPManager()
// Generate OTP for a specific email with an expiration time of 5 minutes
email := "example@example.com"
token, err := manager.GenerateOTP(email, 5*time.Minute)
if err != nil {
fmt.Printf("Error generating OTP: %v\n", err)
return
}
// Simulate sending the OTP via email
fmt.Printf("OTP: %s\n", token)
// Simulate user entering the OTP for verification
enteredToken := "abc123" // Replace with the OTP entered by the user
// Verify the OTP
isValid := manager.VerifyOTP(email, enteredToken)
if isValid {
fmt.Println("Verification successful!")
// Mark the user's account as verified
// Update the verification status in the user table or session data
} else {
fmt.Println("Verification failed!")
// Handle the verification failure
}
}
In this example, the OTPManager
struct manages the generation and verification of OTPs. The GenerateOTP
method generates a random token/OTP, associates it with the provided email, and stores it in the otps
map along with its expiration time. The VerifyOTP
method retrieves the stored OTP for the email and compares it with the provided token to validate the verification.
You can integrate the OTPManager
into your application's
verification flow, associating each generated OTP with the user's email or session data for proper verification. Remember to adjust the length and expiration time of the OTPs as per your specific requirements.