Authenticate Go-GraphQL with JWT

Protect your API with JWT

David Yappeter
Geek Culture
Published in
6 min readAug 24, 2021

--

When you develop a web application, of course, authentication and authorization are normal things to apply to your application; to limit the guest access to some content of your resource.
There are several ways of authentication and authorization of a web application, one of the most famous ones is JWT.

What is JWT?

JWT (JSON Web Token) is a media to securely transmitting information between parties using a JSON format. JWT can be signed with a secret key (HMAC Algorithm) or Public Key (RSA or ECDSA)

JWT Structure is split into 3 parts xxxxx.yyyyy.zzzzz:

  • Header
  • Payload
  • Signature
https://jwt.io

Header contains the algorithm used by the token, and ‘JWT’.
Payload contains the claims (information) about the data.
Signature contains the sign of hashed Header, Payload, secret, and algorithm, this part is used to verify the JSON is valid.

Requirement

  • github.com/99designs/gqlgen
  • github.com/dgrijalva/jwt-go
  • gorm.io/gorm
  • github.com/gorilla/mux
  • github.com/google/uuid
  • docker & docker-compose (database / optional)

And of course, some basics of go programming and GraphQL schema. So you guys can understand better what I do.

With gqlgen, we will generate our GraphQL server. For the database, we will use MySQL and connect to the database using GORM, mux for the HTTP Router, and jwt-go to generate and validate the JWT.

Repository: https://github.com/david-yappeter/go-graphql-jwt

Graphql Server

First of all, we will create the project directory and initialize go modules:

The project directory should look like this

After gqlgen init

and then we will create our User model in the schema.graphqls :

to help you generate code faster, try to write this down in your graph/resolver.go

//go:generate go run github.com/99designs/gqlgen

then you will be able to generate the code by running go generate ./... on your terminal.

After generating your code, there should be some leftover code that gives you an error, just delete that part.

Remove leftover code

And then we will move our User model outside to avoid overwritten by the generator.

We will add Password attribute to the model so GORM can insert automatically insert the password.

Add the gorm tag to the model, this will help us with the table migration later on.

Database Configuration

The next step is to create our database connection, we will use GORM which is go ORM that helps us develop faster and maintaining code better.

config/database.go

Optionally we can add a database close on our server.go

database defer close (optional)

MySQL Database with Docker & Docker-Compose

Add a docker-compose.yml file on your root directory:

And run it by using this command:

docker-compose up -d

Don’t forget to add the .env in the root directory for database configuration, example below:

JWT & User Service

We will write our JWT & user service on service directory.
Jwt will have JwtGenerate and JwtValidate .
User will have UserCreate ,UserGetByID, and UserGetByEmail
Auth will have UserRegister and UserLogin .

service/jwt.go

With jwt.NewWithClaims it will create a token with our Custom Claim that we pass in the second parameter, in this example JwtCustomClaim . After the token is created, we need to sign the token with our JWT_SECRET value to make the token secure.

To validate the token, later on, we use JwtValidate which take the token as a parameter and return *jwt.Token as a return value.
How jwt.ParseWithClaims callback works are, first, we check the token Signing Method, we use a secret HS256 to sign the token, so we check if the Signing method of the token is *jwt.SigningMethodHMAC or not, then if it is a yes, we will return the secret, so the Jwt.ParseWithClaims will return <nil> error if the ‘secret’ is valid.

We will take the JwtCustomClaim value later on from *Jwt.Token in the middleware section.

Before we move to User service, we will create a password hasher tools first.

tools/bcrypt.go

Hash using Bcrypt

Then we will create our User service

service/user.go

Before we create our user, first we hash the password and then give random uuid generated by github.com/google/uuid .

Then move on to auth.go service.

service/auth.go

In UserRegister , we will find the user first. If the user is not found, we can create the account and return the JWT.

For UserLogin , we will find the user. If the user is found, we return the JWT.

Then we will apply the function to the schema.resolvers.go

graph/schema.resolvers.go

assign the function

Add Database Table Migration

We will create the migration on migration directory.

migration/migration.go

And we need to apply it to the server.go :

apply the migration to server.go

Authentication Middleware & Directives

For the middleware, we will create it on middlewares directory.

middlewares/auth.go

AuthMiddleware will be assigned to mux router, later on, it will get the value of Authorization from the header and validate the token and assign it to the request context , later we can use the value by calling CtxValue that get the CustomClaim from the context .

After this, we will create Auth the directive which will be applied on GraphQL protected resources, we will need to change our graph/schema.graphqls

graph/schema.graphqls

Then generate our resolvers again. ‘Protected’ will be added in schema.resolvers.go

Add a simple return “Success”, nil.

The last thing we need to do is, make the function and apply it to the directive

Apply it to the server.go by copying this part

Apply directives

Our part for middleware and directives is done

Applying Middleware

We will create new mux Router on server.go

Initialize router and apply middleware

router.Use(middlewares.AuthMiddleware) will do the job for authentication and Auth the directive will handle the authorization inside the GraphQL.

Testing

Run our code by using go run server.go .

Access Protected without JWT

When we try to access the Protected without JWT it will return us Access Denied which we got from the directive.

So let's try to register users & log in.

Register User
Log in

Now I will try to add the token to Header Authorization

Access protected with token

Now it doesn’t return any error.

This is the end of Go-GraphQL JWT article. Hope it helps you :).

--

--