Created
February 4, 2020 00:40
-
-
Save victorsteven/f1c5154cd1d9b269876e00990ecaeed0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"github.com/dgrijalva/jwt-go" | |
"github.com/go-redis/redis/v7" | |
"github.com/twinj/uuid" | |
"net/http" | |
"os" | |
"strconv" | |
"strings" | |
"time" | |
) | |
var ( | |
client *redis.Client | |
) | |
func init() { | |
//Initializing redis | |
dsn := os.Getenv("REDIS_DSN") | |
if len(dsn) == 0 { | |
dsn = "localhost:6379" | |
} | |
client = redis.NewClient(&redis.Options{ | |
Addr: dsn, //redis port | |
}) | |
_, err := client.Ping().Result() | |
if err != nil { | |
panic(err) | |
} | |
} | |
type AccessDetails struct { | |
AccessUuid string | |
UserId uint64 | |
} | |
type TokenDetails struct { | |
AccessToken string | |
RefreshToken string | |
AccessUuid string | |
RefreshUuid string | |
AtExpires int64 | |
RtExpires int64 | |
} | |
func CreateToken(userid uint64) (*TokenDetails, error) { | |
td := &TokenDetails{} | |
td.AtExpires = time.Now().Add(time.Minute * 10).Unix() | |
td.AccessUuid = uuid.NewV4().String() | |
td.RtExpires = time.Now().Add(time.Minute * 60).Unix() | |
td.RefreshUuid = uuid.NewV4().String() | |
var err error | |
//Creating Access Token | |
os.Setenv("ACCESS_SECRET", "jdnfksdmfksd") //this should be in an env file | |
atClaims := jwt.MapClaims{} | |
atClaims["authorized"] = true | |
atClaims["access_uuid"] = td.AccessUuid | |
atClaims["user_id"] = userid | |
atClaims["exp"] = td.AtExpires | |
at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims) | |
td.AccessToken, err = at.SignedString([]byte(os.Getenv("API_SECRET"))) | |
if err != nil { | |
return nil, err | |
} | |
//Creating Refresh Token | |
os.Setenv("REFRESH_SECRET", "mcmvmkmsdnfsdmfdsjf") //this should be in an env file | |
rtClaims := jwt.MapClaims{} | |
rtClaims["refresh_uuid"] = td.RefreshUuid | |
rtClaims["user_id"] = userid | |
rtClaims["exp"] = td.RtExpires | |
rt := jwt.NewWithClaims(jwt.SigningMethodHS256, rtClaims) | |
td.RefreshToken, err = rt.SignedString([]byte(os.Getenv("API_SECRET_REFRESH"))) | |
if err != nil { | |
return nil, err | |
} | |
return td, nil | |
} | |
func TokenValid(r *http.Request) error { | |
token, err := VerifyToken(r) | |
if err != nil { | |
return err | |
} | |
if _, ok := token.Claims.(jwt.Claims); !ok && !token.Valid { | |
return err | |
} | |
return nil | |
} | |
func VerifyToken(r *http.Request) (*jwt.Token, error) { | |
tokenString := ExtractToken(r) | |
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { | |
//Make sure that the token method conform to "SigningMethodHMAC" | |
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { | |
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) | |
} | |
return []byte(os.Getenv("API_SECRET")), nil | |
}) | |
if err != nil { | |
return nil, err | |
} | |
return token, nil | |
} | |
//get the token from the request body | |
func ExtractToken(r *http.Request) string { | |
bearToken := r.Header.Get("Authorization") | |
//normally Authorization the_token_xxx | |
strArr := strings.Split(bearToken, " ") | |
if len(strArr) == 2 { | |
return strArr[1] | |
} | |
return "" | |
} | |
func ExtractTokenAuth(r *http.Request) (*AccessDetails, error) { | |
token, err := VerifyToken(r) | |
if err != nil { | |
return nil, err | |
} | |
claims, ok := token.Claims.(jwt.MapClaims) //the token claims should conform to MapClaims | |
if ok && token.Valid { | |
accessUuid, ok := claims["access_uuid"].(string) //convert the interface to string | |
if !ok { | |
return nil, err | |
} | |
userId, err := strconv.ParseUint(fmt.Sprintf("%.f", claims["user_id"]), 10, 64) | |
if err != nil { | |
return nil, err | |
} | |
return &AccessDetails{ | |
AccessUuid: accessUuid, | |
UserId: userId, | |
}, nil | |
} | |
return nil, err | |
} | |
//Save token metadata to Redis | |
func CreateAuth(userid uint64, td *TokenDetails) error { | |
at := time.Unix(td.AtExpires, 0) //converting Unix to UTC(to Time object) | |
rt := time.Unix(td.RtExpires, 0) | |
now := time.Now() | |
errAccess := client.Set(td.AccessUuid, strconv.Itoa(int(userid)), at.Sub(now)).Err() | |
if errAccess != nil { | |
return errAccess | |
} | |
errRefresh := client.Set(td.RefreshUuid, strconv.Itoa(int(userid)), rt.Sub(now)).Err() | |
if errRefresh != nil { | |
return errRefresh | |
} | |
return nil | |
} | |
//Check the metadata saved | |
func FetchAuth(authD *AccessDetails) (uint64, error) { | |
userid, err := client.Get(authD.AccessUuid).Result() | |
if err != nil { | |
return 0, err | |
} | |
userID, _ := strconv.ParseUint(userid, 10, 64) | |
return userID, nil | |
} | |
//Once a user row in the auth table | |
func DeleteToken(givenUuid string) (int64,error) { | |
deleted, err := client.Del(givenUuid).Result() | |
if err != nil { | |
return 0, err | |
} | |
return deleted, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment