Authenticate JWT in Go & GraphQL
[Part 2] Docker Golang GraphQL Build An Api And Deployment on DigitalOcean. Part 1 is here

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..."
}