Authenticate JWT in Go & GraphQL

[Part 2] Docker Golang GraphQL Build An Api And Deployment on DigitalOcean. Part 1 is here

Tabvn
2 min readJul 7, 2019

Security user password

First of all we do need encode plan text password and keep it security and store in MySQL. Package in Go we do use in this tutorial is bcrypt

here are two function for encode password and compare password

Video

import "golang.org/x/crypto/bcrypt"func HashPassword(originalPassword string) (string, error) {
pass, err := bcrypt.GenerateFromPassword([]byte(originalPassword), 10)
return string(pass), err
}
func ComparePassword(password, hash string) bool {
if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil {
return true
}
return false
}

Json Web Token Jwt

we do use this package in Go to generate a token and decode jwt token from header of client via GraphQL

jwt.go

package dexp

import "github.com/dgrijalva/jwt-go"
var mySigningKey = []byte("dexp.io")

func JwtDecode(token string) (*jwt.Token, error) {
return jwt.ParseWithClaims(token, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return mySigningKey, nil
})
}
func JwtCreate(userID int, expiredAt int64) string {
claims := UserClaims{
userID,
jwt.StandardClaims{
ExpiresAt: expiredAt,
Issuer: "dexp",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, _ := token.SignedString(mySigningKey)
return ss
}

Middware

here is fully working Middware.go we can use in this tutorial

package dexp

import (
"context"
"github.com/dgrijalva/jwt-go"
"net"
"net/http"
"strings"
)

type UserAuth struct {
UserID int
Roles []string
IPAddress string
Token string
}

var userCtxKey = &contextKey{"user"}

type contextKey struct {
name string
}
type UserClaims struct {
UserId int `json:"user_id"`
jwt.StandardClaims
}

func Middleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := TokenFromHttpRequest(r)

userId := UserIDFromToken(token)

ip, _, _ := net.SplitHostPort(r.RemoteAddr)
userAuth := UserAuth{
UserID: userId,
IPAddress: ip,
Token: token,
}

// put it in context
ctx := context.WithValue(r.Context(), userCtxKey, &userAuth)
// and call the next with our new context
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
}
func TokenFromHttpRequest(r *http.Request) string {
reqToken := r.Header.Get("Authorization")
var tokenString string
splitToken := strings.Split(reqToken, "Bearer ")
if len(splitToken) > 1 {
tokenString = splitToken[1]
}
return tokenString
}
func UserIDFromToken(tokenString string) int {

token, err := JwtDecode(tokenString)
if err != nil {
return 0
}
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
if claims == nil {
return 0
}
return claims.UserId
} else {
return 0
}
}
func ForContext(ctx context.Context) *UserAuth {
raw := ctx.Value(userCtxKey)
if raw == nil {
return nil
}
return raw.(*UserAuth)
}
func GetAuthFromContext(ctx context.Context) *UserAuth {
return ForContext(ctx)
}

Login Resolve Func

func (r *mutationResolver) Login(ctx context.Context, email string, password string) (*Token, error) {


user , err := FindUserByEmail(email)

if err != nil || user == nil{
return nil, errors.New("user not found")
}

if !ComparePassword(password, user.Password){
return nil, errors.New("password does not correct")
}

expiredAt := time.Now().Add(time.Hour * 1).Unix()
obj := &Token{
Token: JwtCreate(user.ID, expiredAt),
ExpiredAt: int(expiredAt),
}

return obj, nil
}

Request With Jwt in GraphQL

{
"Authorization": "Bearer xyz..."
}

--

--

Tabvn

i’m from a nice city in Vietnam called Danang, where live and did my studies. I love programming, coffee and spending my free time teaching myself new skills.