Skip to content

πŸ”₯ Example of microservice JWT authentication using MongoDB and clean architecture principles.

License

Notifications You must be signed in to change notification settings

ArtoriasCode/jwtgo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

53 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

jwtgo

A Go (Golang) backend clean architecture project with API Gateway, Microservices, MongoDB and JWT Authentication.

The project was created for educational purposes and is not ideal. It has its shortcomings, which are gradually being corrected.

Project architecture

The architecture of a web application consists of these layers:

  • Reverse Proxy
  • API Gateway
  • Microservice
  • Database

The architecture of the microservice application consists of these layers:

  • Server
  • Service
  • Repository

Image

The API is accessed via Reverse Proxy, in our case it is Nginx. It handles all incoming requests and prevents access to microservices and API gateway directly.

Major packages used in project

  • Gin: Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
  • gRPC: The Go implementation of gRPC: A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. For more information see the Go gRPC docs, or jump directly into the quick start.
  • protobuf: Go support for Google's protocol buffers.
  • MongoDB: The Official Golang driver for MongoDB.
  • JWT: Go implementation of JSON Web Tokens (JWT).
  • Cleanenv: Clean and minimalistic environment configuration reader for Golang.
  • Bcrypt: Package bcrypt implements Provos and MaziΓ¨res's bcrypt adaptive hashing algorithm.
  • Logrus: Structured, pluggable logging for Go.
  • Validator: Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving.

Request flow without JWT authentication middleware

Image

Request flow with JWT authentication middleware

Image

How to run the project?

First, download it and navigate to the root directory:

# Move to your workspace
cd your-workspace

# Clone the project into your workspace
git clone https://github.com/ArtoriasCode/jwtgo.git

# Move to the project root directory
cd jwtgo

Run with Docker

  • Create a .env file, similar to .env.sample.

  • Install the Docker, Protoc, Taskfile if it is not installed on your computer.

  • Fill in the .env file with your data.

  • Run the application build with the following command:

    task build
  • Access API using http://localhost.

Examples of API requests and responses

SignUp endpoint

  • Request:

    curl --location 'http://localhost/api/v1/auth/signup' \
    --header 'Content-Type: application/json' \
    --data-raw '{
      "email": "[email protected]",
      "password": "securepassword"
    }'
    
  • Response:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "message": "User successfully registered"
    }

SignIn endpoint

  • Request:

    curl --location 'http://localhost/api/v1/auth/signin' \
    --header 'Content-Type: application/json' \
    --data-raw '{
      "email": "[email protected]",
      "password": "securepassword"
    }'
    
  • Response:

    HTTP/1.1 200 OK
    Content-Type: application/json
    Set-Cookie: access_token=access_token; Path=/; HttpOnly; SameSite=Strict
    Set-Cookie: refresh_token=refresh_token; Path=/; HttpOnly; SameSite=Strict
    
    {
      "message": "User successfully logged in"
    }

SignOut endpoint

  • Request:

    curl --location 'http://localhost/api/v1/auth/signout' \
    --header 'Content-Type: application/json' \
    -b 'access_token=access_token; refresh_token=refresh_token'
    
  • Response:

    HTTP/1.1 200 OK
    Content-Type: application/json
    Set-Cookie: access_token=access_token; Path=/; HttpOnly; SameSite=Strict
    Set-Cookie: refresh_token=refresh_token; Path=/; HttpOnly; SameSite=Strict
    
    {
      "message": "User successfully logged out"
    }

Refresh endpoint

  • Request:

    curl --location 'http://localhost/api/v1/auth/refresh' \
    --header 'Content-Type: application/json' \
    -b 'access_token=access_token; refresh_token=refresh_token'
    
  • Response:

    HTTP/1.1 200 OK
    Content-Type: application/json
    Set-Cookie: access_token=access_token; Path=/; HttpOnly; SameSite=Strict
    Set-Cookie: refresh_token=refresh_token; Path=/; HttpOnly; SameSite=Strict
    
    {
      "message": "Tokens successfully updated"
    }

Complete project folder structure

β”œβ”€β”€ build
β”‚   └── package
β”‚       β”œβ”€β”€ api.Dockerfile
β”‚       β”œβ”€β”€ auth.Dockerfile
β”‚       └── user.Dockerfile
β”œβ”€β”€ cmd
β”‚   β”œβ”€β”€ api
β”‚   β”‚   └── main.go
β”‚   β”œβ”€β”€ auth
β”‚   β”‚   └── main.go
β”‚   └── user
β”‚       └── main.go
β”œβ”€β”€ configs
β”‚   └── nginx.conf
β”œβ”€β”€ deployments
β”‚   └── docker-compose.yaml
β”œβ”€β”€ internal
β”‚   β”œβ”€β”€ app
β”‚   β”‚   β”œβ”€β”€ api
β”‚   β”‚   β”‚   β”œβ”€β”€ config
β”‚   β”‚   β”‚   β”‚   └── config.go
β”‚   β”‚   β”‚   β”œβ”€β”€ controller
β”‚   β”‚   β”‚   β”‚   └── http
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”‚       β”‚   └── user.go
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ mapper
β”‚   β”‚   β”‚   β”‚       β”‚   └── user.go
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ middleware
β”‚   β”‚   β”‚   β”‚       β”‚   β”œβ”€β”€ security.go
β”‚   β”‚   β”‚   β”‚       β”‚   └── validation.go
β”‚   β”‚   β”‚   β”‚       └── v1
β”‚   β”‚   β”‚   β”‚           └── auth.go
β”‚   β”‚   β”‚   └── main.go
β”‚   β”‚   β”œβ”€β”€ auth
β”‚   β”‚   β”‚   β”œβ”€β”€ config
β”‚   β”‚   β”‚   β”‚   └── config.go
β”‚   β”‚   β”‚   β”œβ”€β”€ interface
β”‚   β”‚   β”‚   β”‚   └── service
β”‚   β”‚   β”‚   β”‚       └── auth.go
β”‚   β”‚   β”‚   β”œβ”€β”€ server
β”‚   β”‚   β”‚   β”‚   └── grpc
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”‚       β”‚   └── user.go
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ mapper
β”‚   β”‚   β”‚   β”‚       β”‚   └── user.go
β”‚   β”‚   β”‚   β”‚       └── v1
β”‚   β”‚   β”‚   β”‚           └── auth.go
β”‚   β”‚   β”‚   β”œβ”€β”€ service
β”‚   β”‚   β”‚   β”‚   └── auth.go
β”‚   β”‚   β”‚   └── main.go
β”‚   β”‚   └── user
β”‚   β”‚       β”œβ”€β”€ adapter
β”‚   β”‚       β”‚   └── mongodb
β”‚   β”‚       β”‚       β”œβ”€β”€ entity
β”‚   β”‚       β”‚       β”‚   └── user.go
β”‚   β”‚       β”‚       β”œβ”€β”€ mapper
β”‚   β”‚       β”‚       β”‚   └── user.go
β”‚   β”‚       β”‚       └── repository
β”‚   β”‚       β”‚           └── user.go
β”‚   β”‚       β”œβ”€β”€ config
β”‚   β”‚       β”‚   └── config.go
β”‚   β”‚       β”œβ”€β”€ entity
β”‚   β”‚       β”‚   └── user.go
β”‚   β”‚       β”œβ”€β”€ interface
β”‚   β”‚       β”‚   β”œβ”€β”€ repository
β”‚   β”‚       β”‚   β”‚   └── user.go
β”‚   β”‚       β”‚   └── service
β”‚   β”‚       β”‚       └── user.go
β”‚   β”‚       β”œβ”€β”€ server
β”‚   β”‚       β”‚   └── grpc
β”‚   β”‚       β”‚       β”œβ”€β”€ dto
β”‚   β”‚       β”‚       β”‚   └── user.go
β”‚   β”‚       β”‚       β”œβ”€β”€ mapper
β”‚   β”‚       β”‚       β”‚   └── user.go
β”‚   β”‚       β”‚       └── v1
β”‚   β”‚       β”‚           └── user.go
β”‚   β”‚       β”œβ”€β”€ service
β”‚   β”‚       β”‚   └── user.go
β”‚   β”‚       └── main.go
β”‚   └── pkg
β”‚       β”œβ”€β”€ error
β”‚       β”‚   β”œβ”€β”€ auth.go
β”‚       β”‚   β”œβ”€β”€ jwt.go
β”‚       β”‚   β”œβ”€β”€ repository.go
β”‚       β”‚   └── server.go
β”‚       β”œβ”€β”€ interface
β”‚       β”‚   └── service
β”‚       β”‚       β”œβ”€β”€ jwt.go
β”‚       β”‚       └── password.go
β”‚       β”œβ”€β”€ proto
β”‚       β”‚   β”œβ”€β”€ auth
β”‚       β”‚   β”‚   β”œβ”€β”€ auth.pb.go
β”‚       β”‚   β”‚   └── auth_grpc.pb.go
β”‚       β”‚   └── user
β”‚       β”‚       β”œβ”€β”€ user.pb.go
β”‚       β”‚       └── user_grpc.pb.go
β”‚       β”œβ”€β”€ request
β”‚       β”‚   β”œβ”€β”€ schema
β”‚       β”‚   β”‚   └── response.go
β”‚       β”‚   └── response.go
β”‚       └── service
β”‚           β”œβ”€β”€ schema
β”‚           β”‚   └── jwt.go
β”‚           β”œβ”€β”€ jwt.go
β”‚           └── password.go
β”œβ”€β”€ pkg
β”‚   β”œβ”€β”€ client
β”‚   β”‚   └── mongodb.go
β”‚   β”œβ”€β”€ logging
β”‚   β”‚   └── logger.go
β”‚   └── proto
β”‚       β”œβ”€β”€ auth
β”‚       β”‚   └── auth.proto
β”‚       └── user
β”‚           └── user.proto
β”œβ”€β”€ .env
β”œβ”€β”€ .gitignore
β”œβ”€β”€ go.mod
β”œβ”€β”€ go.sum
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md
└── taskfile.yaml