package jwt import ( "fmt" "time" "git.javil.eu/jacob1123/budgeteer" "git.javil.eu/jacob1123/budgeteer/postgres" "github.com/dgrijalva/jwt-go" "github.com/google/uuid" ) // TokenVerifier verifies Tokens. type TokenVerifier struct{} // Token contains everything to authenticate a user. type Token struct { username string name string expiry float64 id uuid.UUID } const ( expiration = 72 secret = "uditapbzuditagscwxuqdflgzpbu´ßiaefnlmzeßtrubiadern" ) // CreateToken creates a new token from username and name. func (tv *TokenVerifier) CreateToken(user *postgres.User) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "usr": user.Email, "name": user.Name, "exp": time.Now().Add(time.Hour * expiration).Unix(), "id": user.ID, }) // Generate encoded token and send it as response. t, err := token.SignedString([]byte(secret)) if err != nil { return "", fmt.Errorf("create token: %w", err) } return t, nil } var ( ErrUnexpectedSigningMethod = fmt.Errorf("unexpected signing method") ErrInvalidToken = fmt.Errorf("token is invalid") ErrTokenExpired = fmt.Errorf("token has expired") ) // VerifyToken verifys a given string-token. func (tv *TokenVerifier) VerifyToken(tokenString string) (budgeteer.Token, error) { token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("method '%v': %w", token.Header["alg"], ErrUnexpectedSigningMethod) } return []byte(secret), nil }) if err != nil { return nil, fmt.Errorf("parse jwt: %w", err) } claims, err := verifyToken(token) if err != nil { return nil, fmt.Errorf("verify jwt: %w", err) } tkn := &Token{ username: claims["usr"].(string), name: claims["name"].(string), expiry: claims["exp"].(float64), id: uuid.MustParse(claims["id"].(string)), } return tkn, nil } func verifyToken(token *jwt.Token) (jwt.MapClaims, error) { if !token.Valid { return nil, ErrInvalidToken } claims, ok := token.Claims.(jwt.MapClaims) if !ok { return nil, ErrInvalidToken } if !claims.VerifyExpiresAt(time.Now().Unix(), true) { return nil, ErrTokenExpired } return claims, nil } func (t *Token) GetName() string { return t.name } func (t *Token) GetUsername() string { return t.username } func (t *Token) GetExpiry() float64 { return t.expiry } func (t *Token) GetID() uuid.UUID { return t.id }