You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
1.9 KiB
Go
90 lines
1.9 KiB
Go
package client
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
const tokenExpirationSeconds = 60
|
|
|
|
type TokenManager struct {
|
|
issuer string
|
|
privateKey string
|
|
}
|
|
|
|
func (t *TokenManager) CreateJwt() (string, error) {
|
|
if t.issuer == "" || t.privateKey == "" {
|
|
return "", errors.New("missing required field issuer or private key")
|
|
}
|
|
|
|
key, err := t.getRsaPrivateKey()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var header = struct {
|
|
Algorithm string `json:"alg"`
|
|
Type string `json:"typ"`
|
|
}{
|
|
"RS256",
|
|
"JWT",
|
|
}
|
|
var payload = struct {
|
|
Issuer string `json:"iss"`
|
|
Expiration int64 `json:"exp"`
|
|
}{
|
|
t.issuer,
|
|
time.Now().Unix() + tokenExpirationSeconds,
|
|
}
|
|
|
|
headerJson, _ := json.Marshal(&header)
|
|
payloadJson, _ := json.Marshal(&payload)
|
|
pkg := base64.RawURLEncoding.EncodeToString(headerJson) + "." + base64.RawURLEncoding.EncodeToString(payloadJson)
|
|
|
|
if signature, err := t.sign([]byte(pkg), key); err != nil {
|
|
return "", err
|
|
} else {
|
|
return pkg + "." + base64.RawURLEncoding.EncodeToString(signature), nil
|
|
}
|
|
}
|
|
|
|
func (t *TokenManager) sign(data []byte, privateKey *rsa.PrivateKey) ([]byte, error) {
|
|
h := sha256.New()
|
|
h.Write(data)
|
|
d := h.Sum(nil)
|
|
return rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, d)
|
|
}
|
|
|
|
func (t *TokenManager) getRsaPrivateKey() (*rsa.PrivateKey, error) {
|
|
block, _ := pem.Decode([]byte(t.privateKey))
|
|
if block == nil {
|
|
return nil, errors.New("invalid private key format")
|
|
}
|
|
|
|
switch block.Type {
|
|
case "PRIVATE KEY":
|
|
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return key.(*rsa.PrivateKey), nil
|
|
case "RSA PRIVATE KEY":
|
|
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return key, nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported key type %q", block.Type)
|
|
}
|
|
}
|