Files
summercms/bouncer/mint.go
2026-09-22 13:34:58 +02:00

58 lines
1.4 KiB
Go

package bouncer
import (
"crypto/rand"
"encoding/hex"
"fmt"
"strings"
"time"
"github.com/golang-jwt/jwt/v5"
)
// prvHash is sha1("Golem15\User\Models\User"), the lock-subject PHP jwt-auth
// stamps on every user token.
const prvHash = "a867434cbc213adfbe78a02bed7082a6bd99c883"
type registeredClaims struct {
jwt.RegisteredClaims
Prv string `json:"prv,omitempty"`
}
// Mint signs an HS256 token whose iss is the full URL of the minting endpoint.
// The returned jti is the token's own jti claim.
func Mint(secret, sub, issuerURL string, ttl time.Duration) (string, string, error) {
if strings.TrimSpace(secret) == "" {
return "", "", fmt.Errorf("bouncer: jwt secret is empty")
}
jti, err := newJTI()
if err != nil {
return "", "", err
}
now := time.Now()
claims := registeredClaims{
RegisteredClaims: jwt.RegisteredClaims{
Issuer: issuerURL,
Subject: sub,
ExpiresAt: jwt.NewNumericDate(now.Add(ttl)),
NotBefore: jwt.NewNumericDate(now),
IssuedAt: jwt.NewNumericDate(now),
ID: jti,
},
Prv: prvHash,
}
signed, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
if err != nil {
return "", "", err
}
return signed, jti, nil
}
func newJTI() (string, error) {
buf := make([]byte, 16)
if _, err := rand.Read(buf); err != nil {
return "", err
}
return hex.EncodeToString(buf), nil
}