package tokens import ( "fmt" "gitea.deepak.science/deepak/gogmagog/models" "github.com/go-chi/jwtauth" "github.com/lestrrat-go/jwx/jwt" "net/http" "time" ) // Toker represents a tokenizer, capable of encoding and verifying tokens. type Toker interface { EncodeUser(user *models.UserNoPassword) string DecodeTokenString(tokenString string) (*UserToken, error) Authenticator(http.Handler) http.Handler } type jwtToker struct { tokenAuth *jwtauth.JWTAuth } // New returns a default Toker for a given secret key. func New(key string) Toker { return &jwtToker{tokenAuth: jwtauth.New("HS256", []byte(key), nil)} } func (tok *jwtToker) EncodeUser(user *models.UserNoPassword) string { claims := map[string]interface{}{ "user_id": user.UserID, "username": user.Username, "display_name": user.DisplayName, "iss": "gogmagog.deepak.science", "aud": "gogmagog.deepak.science", } jwtauth.SetIssuedNow(claims) jwtauth.SetExpiryIn(claims, 2*time.Hour) _, tokenString, _ := tok.tokenAuth.Encode(claims) return tokenString } // UserToken represents a decoded jwt token. type UserToken struct { ID int64 Username string } func (tok *jwtToker) DecodeTokenString(tokenString string) (*UserToken, error) { token, err := tok.tokenAuth.Decode(tokenString) if err != nil { return nil, fmt.Errorf("Error decoding token") } // Should never happen, remove soon. // if token == nil { // return nil, fmt.Errorf("Token was nil") // } err = jwt.Validate( token, jwt.WithIssuer("gogmagog.deepak.science"), jwt.WithAudience("gogmagog.deepak.science"), ) if err != nil { return nil, err } userIDRaw, ok := token.Get("user_id") if !ok { return nil, fmt.Errorf("error finding user_id claim") } userID, ok := userIDRaw.(float64) if !ok { return nil, fmt.Errorf("Could not parse [%s] as userID", userIDRaw) } usernameRaw, ok := token.Get("username") if !ok { return nil, fmt.Errorf("error finding username claim") } username, ok := usernameRaw.(string) if !ok { return nil, fmt.Errorf("Could not parse [%s] as username", usernameRaw) } return &UserToken{ID: int64(userID), Username: username}, nil }