58 lines
1.4 KiB
Go
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
|
|
}
|