Building a Secure REST API with GORM, Echo, JWT Token Authentication, and PostgreSQL in Go.
Combining GORM, a robust ORM library for Go, with Echo, a high-performance web framework, along with JWT token-based authentication and PostgreSQL, offers a solid foundation for developing secure and scalable RESTful APIs. In this detailed tutorial, we'll create a practical example showcasing the integration of GORM, Echo, JWT token authentication, and PostgreSQL to build a fully functional and secure REST API in Go.
Prerequisites
Ensure you have the following prerequisites:
Go installed on your machine
PostgreSQL installed and running
Basic knowledge of Go, SQL, and RESTful APIs
Setting Up the Project
Initializing the Project
Start by initializing a new Go module:
go mod init your_project_name
Install the required dependencies:
go get -u github.com/labstack/echo/v4
go get -u github.com/labstack/echo/v4/middleware
go get -u github.com/dgrijalva/jwt-go
go get -u github.com/jinzhu/gorm
go get -u github.com/jinzhu/gorm/dialects/postgres
Creating Database
Create a PostgreSQL database and define a users
table with columns id
, username
, password
, and email
.
Building the Secure REST API
Setting Up Echo Server
Create a new Go file, e.g., main.go
, and set up the Echo server:
package main
import (
"time"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/dgrijalva/jwt-go"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
var (
db *gorm.DB
)
func init() {
var err error
dsn := "postgresql://user:password@localhost/database_name?sslmode=disable" // Update with your database credentials
db, err = gorm.Open("postgres", dsn)
if err != nil {
panic("failed to connect to database")
}
// Auto migrate the User model
db.AutoMigrate(&User{})
}
type User struct {
gorm.Model
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
}
func login(c echo.Context) error {
username := c.FormValue("username")
password := c.FormValue("password")
var user User
if err := db.Where("username = ?", username).First(&user).Error; err != nil {
return echo.ErrUnauthorized
}
if user.Password != password {
return echo.ErrUnauthorized
}
// Create JWT token
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["username"] = user.Username
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
t, err := token.SignedString([]byte("secret")) // Replace with your secret key
if err != nil {
return err
}
return c.JSON(200, map[string]string{
"token": t,
})
}
func restricted(c echo.Context) error {
user := c.Get("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
username := claims["username"].(string)
return c.String(200, "Welcome "+username+"!")
}
func main() {
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.POST("/login", login)
r := e.Group("/restricted")
r.Use(middleware.JWT([]byte("secret"))) // Replace with your secret key
r.GET("", restricted)
// Start server
e.Logger.Fatal(e.Start(":8080"))
}
Implementing JWT Token Authentication
Login Endpoint
The POST /login
endpoint authenticates users and generates a JWT token:
func login(c echo.Context) error {
// Authenticating user credentials
// ...
// Creating JWT token
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["username"] = user.Username
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
t, err := token.SignedString([]byte("secret")) // Replace with your secret key
if err != nil {
return err
}
return c.JSON(200, map[string]string{
"token": t,
})
}
Restricted Endpoint
The GET /restricted
endpoint is restricted and requires a valid JWT token for access:
func restricted(c echo.Context) error {
user := c.Get("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
username := claims["username"].(string)
return c.String(200, "Welcome "+username+"!")
}
Registering API Endpoints
Add the new API endpoints to the Echo server:
func main() {
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.POST("/login", login)
r := e.Group("/restricted")
r.Use(middleware.JWT([]byte("secret"))) // Replace with your secret key
r.GET("", restricted)
// Start server
e.Logger.Fatal(e.Start(":8080"))
}
Testing the Secure API
Build and run the application:
go run main.go
Testing Endpoints
To log in and obtain a token:
POST
http://localhost:8080/login
with credentialsTo access restricted endpoint:
GET
http://localhost:8080/restricted
with an obtained token in the Authorization header asBearer YOUR_TOKEN
Conclusion
The integration of GORM with Echo, along with JWT token-based authentication and PostgreSQL, enables the creation of secure and scalable RESTful APIs in Go. This example demonstrates the implementation of JWT token authentication to secure endpoints and provides a foundation for building authentication-based APIs in Go.
By extending this example, developers can implement user registration, authorization, token expiration, and further functionalities, leveraging the capabilities of GORM, Echo, and JWT tokens to build robust and secure APIs in Go.
I hope this helps, you!!
More such articles:
https://www.youtube.com/@maheshwarligade
Subscribe to my newsletter
Read articles from Maheshwar Ligade directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Maheshwar Ligade
Maheshwar Ligade
Learner, Love to make things simple, Full Stack Developer, StackOverflower, Passionate about using machine learning, deep learning and AI