Basic Authentication with Golang

Tram Ho

We will learn how to write registration, login, and authentication functions with json web token with Golang and MongoDB database. The full source of this article you can refer to here

1. Initialize directory

The go mod init [tên-module] command will create a file called go.mod , which will help manage the application’s packages. It is similar to implementing npm init inside Javascript and the go.mod file is similar to the package.json file

2. Directory structure

The directory structure will be organized as follows

  • The main.go file is the file we set the general specifications for the server, when running the application, it will run this file.
  • The go.mod file manages how the package (as introduced above).
  • .env stores application environment variables – auth containing json web token handling file
  • database contains files tasked with manipulating MongoDB (connect the database).
  • models defines the data structure to be saved in a collection.
  • routes contain request handler functions for each route
  • tests contain unit test files
  • utils contains some processing functions to use (parse JSON, …)

3. Coding Login and Register

main.go

  • The first line of the main function body uses the godotenv library so that the application can extract environment variables.
  • The following section simply checks for errors.
  • Our application will use the Multiplexer http / router instead of the default Multiplexer in the net/http library.
  • The next 2 lines define 2 routes used to login and register. The handling functions of the corresponding routes are Login and Register in the auth package (folder routes).
  • The server will listen on port 8000

models/User.go : Define the data structure in db

  • Basic User structure consists of 3 username fields, email and password
  • The Hash function passes the string password, then passes the GenerateFromPassword function of the brcypt library to hash. Below is the prototyped of the GenerateFromPassword function.

  • CheckPasswordHash the CheckPasswordHash function compare the submitted user password match the hashed password in the database?

  • Santize function to remove extra spaces, encode special characters of the data (avoid partial injection holes) before saving to the db.

database/connect.go : Connect to the database

As in the previous article, we connect to mongoDB right in the main function and execute the query. However, this is not suitable for writing module splits because other functions in the other package will not use the collection object returned when the connection is successful. Therefore, we will write the connect to DB function in a separate package and the function can be called at any time to execute.

utils/json.go

Since we are writing the server in pure Golang , when returning the response to the client, we need to set the status code for the header , converting the data to json . To simplify the problem, we will write a function, named package res . So at return response will be res.JSON (looks like Express.JS 😁 )

routes/auth.go : Register an account

Initially, we imported a series of packages as above. In addition to the local package, there are some other 3rd party packages.

  • govalidator : Help validate data received from the client.
  • bson : Because the data in MongoDB is saved as bson it is necessary to format the data before querying.

  • The Register function passes three arguments in accordance with the specified prototype of the http / router . In this route we do not need to use params so leave the _ before to skip it.

  • More than the first 10 lines of the function do the job of extracting data sent from the client and validated by govalidator , if the data submitted is invalid, it returns an error of 400 . Then clean the data with the Santize function.
  • collection := db.Connect() : Connect to collection users
  • Next need to check if the username and email already exist in the system, if it exists then return an error to the client. bson.M data type format bson map (key-value). For more details, you can refer to bson go doc
  • Before saving the user to the db, the password needs to be hashed with the Hash function in the package models

Run the app on The beauty of golang, when you go run main.go , it will automatically install the imported packages. As for Node.JS, you need to run npm install before running the app.

Tested by PostMan

  • Sign Up Success

Check in the database to see if there is a record?

  • Registration failed due to duplicate information (return status 409)

  • Registration failed due to missing or incorrect information (return status 400)

auth/jwt.go : Create jsonwebtoken

With the login function, we will use json web token, when the user successfully logs in, the server will return 1 token, the client will save the token (to localStorage for example) and send it to the server for subsequent requests. to identify users without having to log in again.

We will use the jwt-go library to create json web token, the token will be encrypted according to the secret key stored in .env .

routes/auth.go : Login

  • The part that takes data from the form request and validate is similar to the one we have in the Register function.
  • The database query (FindOne) is different from the Decode function in the back. The Decode function will convert the query data back to a map, making it easier to get the hash of the password at the back. For example, the result variable after FindOne will look like this.

  • Next, call the CheckPasswordHash function to see if the password sent from the client when hashed is the same as the password stored in the db?
  • Finally, call the jwt.Create function to generate tokens, we also do not forget to check for possible errors.

Test with Postman

  • Logged in successfully
  • Wrong password
  • The username does not exist in the db

References

Share the news now

Source : Viblo