Go-Swagger : User Authentication & securing API using JWT — Part 1
In my previous article, I have explained on how to register a new user for a website. We saved our password securely using bcrypt
into the database which is a sensitive data. Once, we are done with registration, the next step is to provide login for the registered user.
If you are new to go-swagger, I would recommend you to read the introduction and implementation part of this amazing framework.
For user authentication we have few options such as session
or JWT
(JSON Web Token) based authentication. I will not get into much details of each, but I’ll explain the reason of choosing JWT
over session
briefly.
JWT Vs Session based Authentication:
Major reason for choosing JWT
over session
is because the JWT
is purely stateless. With stateless, I mean that they can be used by server which has multiple instance of backend services running. With session
you will have separate session
for each service instance. Hence, if the load balancer redirects call to a service where the session
info of the user is not present, then the server won’t be able to authenticate the user.
To overcome the session
sharing there are few ways but that would go beyond the scope of this article.
With JWT
, the server issues a token to the client(user) after successful login. Once the token is issued by server, it is stored on the client side and is added as Authorization
in the headers to get access to protected API calls.
Dummy
JWT
: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
The structure of JWT
consists of Header, Payload & Signature separated by dot (“.”) which can be decoded using jwt.io site. Getting into more details of JWT
will again be out of scope for this article, so I’ll try to write a small article on JWT
and link it here later.
Now, that we have some idea about JWT
, we can start working on our small ecommerce website to have user authentication. Lets go step by step:
1. Create “/login” endpoint for authentication
To create the /login
endpoint, we’ll follow the same steps which we followed earlier:
You can visualize the API by pasting it online swagger editor . Please note that we’ll be getting token
as a response (type LoginSuccess
in swagger.yaml
) of this endpoint.
2. Generate Boilerplate go-swagger code for the endpoint :
Once we have the /login
endpoint created in swagger.yaml
, we will generate the respective boilerplate code using:
swagger generate server -f api/swagger.yaml --default-scheme http
This results in creating in below files boilerplate files:
- /models/login_info.go
- /models/login_success.go
- /restapi/operations/user/login.go
- /restapi/operations/user/login_parameters.go
- /restapi/operations/user/login_responses.go
- /restapi/operations/user/login_urlbuilder.go
But we should not be worried about these files as they are generated based on swagger.yaml
3. Code Implementation:
To integrate boilerplate code with our custom code, we need to create a handler file login.go
under ./handler
folder & a dao
package to access user details from MySql
.
This project structure which we are discussing, has already been explained previously. Also, To access login details from Database, we’ll be using the same code structure to create
mysql
client as we have done for user registration in one of my articles.
- We’ll create a
DAO
package which will interact withMySQL
database. Please note that we’ll be injecting the*sql.DB
connection pointer into theFetchUserDetails()
to keep the code loosely coupled.
- Create a
utils/authenticator.go
file, which we’ll be using to generateJWT
token once the password is matched successfully. The below code usesHMAC-SHA
asjwt.SigningMethodHS256
. We also added user details under claims such asemail
,first_name
,last_name
and an expiration time of300
minutes for the generated token. Thetoken
is signed and returned.
- Creating
login.go
to accessdao/customer.go
&utils/authenticator.go
file. Thelogin.go
will perform below operations:
- Fetch User details from
MySql
database. - Since we have encrypted the password using
bcrypt
, we’ll the same package to the compare the login password with encrypted password. - Once it matches, we create a signed token using
utils.GenerateJWT()
- return the response
LoginSuccess
(as defined inswagger.yaml
)
4. Wire-up the endpoint with handler
To finally execute login.go
when we call /login
endpoint, We need to go to configure_e_food.go
file and assign NewUserLoginHandler
with dbclient
:
5. Hit Endpoint to get the token
Once we have the /login
endpoint created and /register
endpoint for registering a new user, spin up the localhost server with
go run cmd\e-food-server\main.go — scheme http — port=8080
Try the postman to get output as below:
The output token can be decoded to know all the details which we have added on server side using authenticator.go
file.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE1OTY5Nzc2MjEsImZuYW1lIjoiU2hhbiIsImxuYW1lIjoiVml2IiwidXNlciI6ImFzZEB0ZXN0LmNvbSJ9.tdhUL-KpDmzSNtV9z6XhUgoTKcVabuOPS3fHAySjSXQ
Make sure to check mark “secret base64 encoded” to view the details on jwt.io
That’s it for this article, in my next article I’ll show how to restrict the API calls so that they are only accessible using the valid JWT
token. In case you want a final structured code, you can refer to the demo e-food-server code base .
I hope that this will help someone who is new with go-swagger
and wants to implement user authentication. You can use the logic of login.go
and authenticator.go
in a normal Go app as well, I have just used it as per go-swagger
framework.
If you like this article, please 👏 clap 👏 few times to encourage me 🐼 to write more.