Home > Backend Development > Golang > Build an OTP-Based Authentication Server with Go: Part 1

Build an OTP-Based Authentication Server with Go: Part 1

Linda Hamilton
Release: 2025-01-05 09:54:39
Original
847 people have browsed it

Build an OTP-Based Authentication Server with Go: Part 1

Getting Started

Begin by creating a new folder for your project and initialize a Go module with the following command:

go mod init github.com/vishaaxl/cheershare

Set up the Project Structure

Start by setting up a new Go project with the following folder structure:

my-otp-auth-server/
├── cmd/
│   └── api/
│       └── main.go
│       └── user.go
│       └── token.go
├── internal/
│   └── data/
│       ├── models.go
│       └── user.go
│       └── token.go
├── docker-compose.yml
├── go.mod
└── Makefile
Copy after login
Copy after login

Next, set up your docker-compose.yml file. This configuration will define the services—PostgreSQL and Redis—that you'll be working with throughout this tutorial.

Setting Up Services with Docker Compose

We will start by configuring the services required for our project. For the backend, we need the following:

  • Redis: We'll use the redis:6 image. This service will configure a password for secure access, expose port 6379, and enforce password authentication using the --requirepass flag to secure Redis access.

  • PostgreSQL: We'll use the postgres:13 image. The service will define a default user, password, and database, expose port 5432 for communication, and persist data with a named volume (postgres_data) to ensure durability.

Optional:

  • Main Backend Service: You can define the main backend service here as well, which will interact with both PostgreSQL and Redis.
// docker-compose.yml
services:
  postgres:
    image: postgres:13
    container_name: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: mysecretpassword
      POSTGRES_DB: cheershare
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:6
    container_name: redis
    environment:
      REDIS_PASSWORD: mysecretpassword
    ports:
      - "6379:6379"
    command: ["redis-server", "--requirepass", "mysecretpassword"]

volumes:
  postgres_data:

Copy after login
Copy after login

Main Backend Service

For routing and handling HTTP requests, we’ll use the github.com/julienschmidt/httprouter package. To install the dependency, run the following command:

go get github.com/julienschmidt/httprouter
Copy after login

Next, create a file at cmd/api/main.go and paste the following code. An explanation for each line is provided in the comments:

//  main.go
package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    "github.com/julienschmidt/httprouter"
)

/*
config struct:
- Holds application-wide configuration settings such as:
  - `port`: The port number on which the server will listen.
  - `env`: The current environment (e.g., "development", "production").
*/
type config struct {
    port int
    env  string
}

/*
applications struct:
- Encapsulates the application's dependencies, including:
  - `config`: The application's configuration settings.
  - `logger`: A logger instance to handle log messages.
*/
type applications struct {
    config config
    logger *log.Logger
}

func main() {
    cfg := &config{
        port: 4000,
        env:  "development",
    }

    logger := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)

    app := &applications{
        config: *cfg,
        logger: logger,
    }

    router := httprouter.New()

    router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
        w.WriteHeader(http.StatusOK)
        fmt.Fprintln(w, "Welcome to the Go application!")
    })

    /*
        Initialize the HTTP server
        - Set the server's address to listen on the specified port.
        - Assign the router as the handler.
        - Configure timeouts for idle, read, and write operations.
        - Set up an error logger to capture server errors.
    */
    srv := &http.Server{
        Addr:         fmt.Sprintf(":%d", app.config.port),
        Handler:      router,
        IdleTimeout:  time.Minute,
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 30 * time.Second,
    }

    app.logger.Printf("Starting server on port %d in %s mode", app.config.port, app.config.env)

    err := srv.ListenAndServe()
    if err != nil {
        app.logger.Fatalf("Could not start server: %s", err)
    }
}

Copy after login

Right now, you can test your setup by starting out server using go run ./cmd/api and sending a request to http://localhost:4000, which will return a welcome message. Next, we’ll define three additional routes to implement our core functionality:

  1. /send-otp: This route will handle sending OTPs to users. It will generate a unique OTP, store it in Redis, and deliver it to the user.

  2. /verify-otp: This route will verify the OTP provided by the user. It will check against the value stored in Redis to confirm the user's identity.

  3. /login: This route will handle user login functionality once the OTP is verified and user is successfully created.

But before we continue, we need a way to store user information like phone number and their one-time password for which we need to connect to the services we defined earlier in the docker-compose.yml file.

Defining Helper Functions

Before implementing the routes, let’s define two essential helper functions. These functions will handle connections to the Redis and PostgreSQL servers, ensuring that our backend can interact with these services.

Modify the 'config' struct to store information about the services. These functions are pretty self-explanatory.

my-otp-auth-server/
├── cmd/
│   └── api/
│       └── main.go
│       └── user.go
│       └── token.go
├── internal/
│   └── data/
│       ├── models.go
│       └── user.go
│       └── token.go
├── docker-compose.yml
├── go.mod
└── Makefile
Copy after login
Copy after login

You can use these functions to establish a connection to the PostgreSQL database and Redis server after starting the services with the docker-compose up -d command.

In the next part, we'll start working on those routes we talked about earlier. This is what your main.go file should look like now.

// docker-compose.yml
services:
  postgres:
    image: postgres:13
    container_name: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: mysecretpassword
      POSTGRES_DB: cheershare
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:6
    container_name: redis
    environment:
      REDIS_PASSWORD: mysecretpassword
    ports:
      - "6379:6379"
    command: ["redis-server", "--requirepass", "mysecretpassword"]

volumes:
  postgres_data:

Copy after login
Copy after login

The above is the detailed content of Build an OTP-Based Authentication Server with Go: Part 1. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template