Files
Gardomatic/internal/auth/token.go
T
kleiax 904d14b64c
CI / test (push) Canceled after 0s
Initial commit
2026-09-12 22:22:17 +02:00

54 lines
1.4 KiB
Go

package auth
import (
"crypto/rand"
"crypto/sha256"
"time"
"gardomatic.kleiax.de/internal/platform/validate"
)
const (
// ScopeActivation identifies account activation tokens.
ScopeActivation = "activation"
// ScopeAuthentication identifies bearer authentication tokens.
ScopeAuthentication = "authentication"
// ScopePasswordReset identifies password reset tokens.
ScopePasswordReset = "password-reset"
)
// Token carries a one-time plaintext token and the hash persisted by storage.
type Token struct {
Plaintext string `json:"token"`
Hash []byte `json:"-"`
UserID int `json:"-"`
Expiry time.Time `json:"expiry"`
Scope string `json:"-"`
}
// NewToken creates a cryptographically random token for a user and scope.
func NewToken(userID int, ttl time.Duration, scope string) Token {
token := Token{
Plaintext: rand.Text(),
UserID: userID,
Expiry: time.Now().Add(ttl),
Scope: scope,
}
hash := sha256.Sum256([]byte(token.Plaintext))
token.Hash = hash[:]
return token
}
// Validate adds token consistency errors to v.
func (tk Token) Validate(v *validate.Validator) {
ValidateTokenPlaintext(v, tk.Plaintext)
}
// ValidateTokenPlaintext checks the expected format of a user-supplied token.
func ValidateTokenPlaintext(v *validate.Validator, tokenPlaintext string) {
v.Check(tokenPlaintext != "", "token", "must be provided")
v.Check(len(tokenPlaintext) == 26, "token", "must be 26 bytes long")
}