Implementing 2FA with SMS, Email, Google OTP, and Pincode in Golang
Two-Factor Authentication (2FA) adds an extra layer of security to your accounts by requiring not just a password but also a second form of verification. In this tutorial, we will learn how to implement 2FA using SMS, email, Google OTP, and pincode in Golang using the Gin framework.
1. Setup
First, let's set up our Golang project. We need to install the necessary packages:
go get github.com/gin-gonic/gin
go get github.com/dgrijalva/jwt-go
go get github.com/sendgrid/sendgrid-go
go get github.com/dgryski/dgoogauth
2. Server Setup
We will create a Gin server and set up routes to handle login and 2FA.
package
mainimport
( "github.com/gin-gonic/gin"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/sendgrid/sendgrid-go"
"github.com/sendgrid/sendgrid-go/helpers/mail"
"github.com/dgryski/dgoogauth"
"math/rand"
"net/http"
"time"
"fmt"
)var otpCode string
{
var otpSecret string = "SECRET" // Google OTP secret key
func main()
r := gin.Default() store := cookie.NewStore([]byte("secret"
)) r.Use(sessions.Sessions("mysession"
, store)) r.LoadHTMLGlob("templates/*"
) r.GET("/"
, home) r.POST("/send-otp"
, sendOTP) r.POST("/verify-otp"
, verifyOTP) r.Run(":8080"
)
}func home(c *gin.Context)
{ c.HTML(http.StatusOK, "index.html", nil
)
}func sendOTP(c *gin.Context)
{ user := c.PostForm("user"
) method := c.PostForm("method"
)
otpCode = generateOTP() if method == "email"
{
sendOTPEmail(user, otpCode) } else if method == "sms"
{
sendOTPSMS(user, otpCode)
} c.HTML(http.StatusOK, "verify.html", gin.H{"method"
: method})
}func verifyOTP(c *gin.Context)
{ userOTP := c.PostForm("otp"
) method := c.PostForm("method"
)
session := sessions.Default(c) if method == "google"
{
otpConfig := &dgoogauth.OTPConfig{
Secret: otpSecret, WindowSize: 3
, HotpCounter: 0
,
}
valid, _ := otpConfig.Authenticate(userOTP) if
valid { c.String(http.StatusOK, "Login Successful"
) return
} } else
{ if
userOTP == otpCode { c.String(http.StatusOK, "Login Successful"
) return
}
} c.String(http.StatusUnauthorized, "Invalid OTP"
)
}func generateOTP() string
{
rand.Seed(time.Now().UnixNano()) otp := fmt.Sprintf("%06d", rand.Intn(1000000
)) return
otp
}func sendOTPEmail(email string, otp string)
{ from := mail.NewEmail("Example User", "test@example.com"
) subject := "Your OTP Code"
, email)
to := mail.NewEmail("Example User" plainTextContent := "Your OTP code is "
+ otp htmlContent := "<strong>Your OTP code is " + otp + "</strong>"
message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent) client := sendgrid.NewSendClient("YOUR_SENDGRID_API_KEY"
)
client.Send(message)
}func sendOTPSMS(phone string, otp string)
{ // Add logic to send OTP via SMS, for example using Twilio API.
}
3. HTML Templates
We need two HTML files: one for login and one for verifying the OTP. Create templates/index.html
and templates/verify.html
.
templates/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form action="/send-otp" method="POST">
<input type="email" name="user" placeholder="Enter your email or phone" required>
<select name="method">
<option value="email">Email</option>
<option value="sms">SMS</option>
<option value="google">Google OTP</option>
</select>
<button type="submit">Send OTP</button>
</form>
</body>
</html>
templates/verify.html
:
<!DOCTYPE html>
<html>
<head>
<title>Verify OTP</title>
</head>
<body>
<h1>Verify OTP</h1>
<form action="/verify-otp" method="POST">
<input type="text" name="otp" placeholder="Enter OTP" required>
<input type="hidden" name="method" value="{{ .method }}">
<button type="submit">Verify</button>
</form>
</body>
</html>
4. Explanation
- Generate OTP: The server generates a random 6-digit OTP.
- Send OTP: Depending on the user's choice, the OTP is sent via email or SMS.
- Verify OTP: The user enters the received OTP, and the server verifies it. If correct, the user is logged in; otherwise, they receive an error message.
- Google OTP: If the user selects Google OTP, the entered OTP is verified against the stored secret key.
Conclusion
This is how you can implement 2FA in your Golang application using SMS, email, Google OTP, and pincode. This additional layer of security helps protect user accounts from unauthorized access. Happy coding!