67 lines
1.6 KiB
Go
67 lines
1.6 KiB
Go
package token
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"time"
|
|
|
|
"aidanwoods.dev/go-paseto"
|
|
)
|
|
|
|
const TokenDuration = 7 * 24 * time.Hour
|
|
|
|
const (
|
|
claimUserID = "uid"
|
|
)
|
|
|
|
// KeyFromHex loads a V4 symmetric key from a 64-char hex string (AUTH_PASETO_KEY).
|
|
func KeyFromHex(h string) (paseto.V4SymmetricKey, error) {
|
|
b, err := hex.DecodeString(h)
|
|
if err != nil {
|
|
return paseto.V4SymmetricKey{}, err
|
|
}
|
|
return paseto.V4SymmetricKeyFromBytes(b)
|
|
}
|
|
|
|
// IssueToken creates a PASETO v4 local (encrypted) token carrying the
|
|
// user ID and a jti that maps to a row in the sessions table.
|
|
func IssueToken(key paseto.V4SymmetricKey, userID, jti string) (string, error) {
|
|
tok := paseto.NewToken()
|
|
tok.SetIssuedAt(time.Now())
|
|
tok.SetNotBefore(time.Now())
|
|
tok.SetExpiration(time.Now().Add(TokenDuration))
|
|
tok.SetJti(jti)
|
|
if err := tok.Set(claimUserID, userID); err != nil {
|
|
return "", err
|
|
}
|
|
return tok.V4Encrypt(key, nil), nil
|
|
}
|
|
|
|
// Claims holds the verified payload extracted from a token.
|
|
type Claims struct {
|
|
UserID string
|
|
JTI string
|
|
}
|
|
|
|
// VerifyToken decrypts and validates a PASETO v4 local token.
|
|
func VerifyToken(key paseto.V4SymmetricKey, raw string) (Claims, error) {
|
|
parser := paseto.NewParser()
|
|
parser.AddRule(paseto.NotExpired())
|
|
parser.AddRule(paseto.ValidAt(time.Now()))
|
|
|
|
tok, err := parser.ParseV4Local(key, raw, nil)
|
|
if err != nil {
|
|
return Claims{}, err
|
|
}
|
|
|
|
var userID string
|
|
if err := tok.Get(claimUserID, &userID); err != nil {
|
|
return Claims{}, errors.New("missing uid claim")
|
|
}
|
|
jti, err := tok.GetJti()
|
|
if err != nil {
|
|
return Claims{}, errors.New("missing jti claim")
|
|
}
|
|
|
|
return Claims{UserID: userID, JTI: jti}, nil
|
|
}
|