token.go raw

   1  package internal
   2  
   3  import (
   4  	"crypto/rsa"
   5  	"crypto/x509"
   6  	"encoding/pem"
   7  	"fmt"
   8  	"time"
   9  
  10  	"github.com/go-jose/go-jose/v4"
  11  	"github.com/go-jose/go-jose/v4/jwt"
  12  )
  13  
  14  type TokenSigner struct {
  15  	PrivateKey string
  16  	KeyID      string
  17  	Audience   string
  18  	Issuer     string
  19  	Subject    string
  20  }
  21  
  22  func (input *TokenSigner) GetJWT() (string, error) {
  23  	signer, err := getRSASigner(input.PrivateKey, input.KeyID)
  24  	if err != nil {
  25  		return "", err
  26  	}
  27  
  28  	issuedAt := time.Now()
  29  	expiresAt := issuedAt.Add(5 * time.Minute)
  30  
  31  	payload := Payload{IssuedAt: issuedAt.Unix(), Expiry: expiresAt.Unix(), Audience: input.Audience, Issuer: input.Issuer, Subject: input.Subject}
  32  	token, err := payload.buildToken(&signer)
  33  
  34  	return token, err
  35  }
  36  
  37  func getRSASigner(privateKey, keyID string) (jose.Signer, error) {
  38  	parsedKey, err := parseRSAKey(privateKey)
  39  	if err != nil {
  40  		return nil, err
  41  	}
  42  
  43  	key := jose.SigningKey{Algorithm: jose.RS256, Key: parsedKey}
  44  
  45  	signerOpts := jose.SignerOptions{}
  46  	signerOpts.WithType("JWT")
  47  	signerOpts.WithHeader("kid", keyID)
  48  
  49  	rsaSigner, err := jose.NewSigner(key, &signerOpts)
  50  	if err != nil {
  51  		return nil, fmt.Errorf("failed to create JWS RSA256 signer: %w", err)
  52  	}
  53  
  54  	return rsaSigner, nil
  55  }
  56  
  57  type Payload struct {
  58  	IssuedAt int64  `json:"iat"`
  59  	Expiry   int64  `json:"exp"`
  60  	Audience string `json:"aud"`
  61  	Issuer   string `json:"iss"`
  62  	Subject  string `json:"sub"`
  63  }
  64  
  65  func (payload *Payload) buildToken(signer *jose.Signer) (string, error) {
  66  	builder := jwt.Signed(*signer).Claims(payload)
  67  
  68  	token, err := builder.Serialize()
  69  	if err != nil {
  70  		return "", fmt.Errorf("failed to build JWT: %w", err)
  71  	}
  72  
  73  	return token, nil
  74  }
  75  
  76  func parseRSAKey(pemString string) (*rsa.PrivateKey, error) {
  77  	block, _ := pem.Decode([]byte(pemString))
  78  
  79  	key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  80  	if err != nil {
  81  		return nil, fmt.Errorf("failed to parse private key: %w", err)
  82  	}
  83  
  84  	return key, nil
  85  }
  86