github.com/clerkinc/clerk-sdk-go@v1.49.1/clerk/tokens_options.go (about)

     1  package clerk
     2  
     3  import (
     4  	"crypto/x509"
     5  	"encoding/pem"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/go-jose/go-jose/v3"
    11  )
    12  
    13  // VerifyTokenOption describes a functional parameter for the VerifyToken method
    14  type VerifyTokenOption func(*verifyTokenOptions) error
    15  
    16  // WithAuthorizedParty allows to set the authorized parties to check against the azp claim of the session token
    17  func WithAuthorizedParty(parties ...string) VerifyTokenOption {
    18  	return func(o *verifyTokenOptions) error {
    19  		authorizedParties := make(map[string]struct{})
    20  		for _, party := range parties {
    21  			authorizedParties[party] = struct{}{}
    22  		}
    23  
    24  		o.authorizedParties = authorizedParties
    25  		return nil
    26  	}
    27  }
    28  
    29  // WithLeeway allows to set a custom leeway that gives some extra time to the token to accomodate for clock skew, etc.
    30  func WithLeeway(leeway time.Duration) VerifyTokenOption {
    31  	return func(o *verifyTokenOptions) error {
    32  		o.leeway = leeway
    33  		return nil
    34  	}
    35  }
    36  
    37  // WithJWTVerificationKey allows to set the JWK to use for verifying tokens without the need to download or cache any JWKs at runtime
    38  func WithJWTVerificationKey(key string) VerifyTokenOption {
    39  	return func(o *verifyTokenOptions) error {
    40  		// From the Clerk docs: "Note that the JWT Verification key is not in
    41  		// PEM format, the header and footer are missing, in order to be shorter
    42  		// and single-line for easier setup."
    43  		if !strings.HasPrefix(key, "-----BEGIN") {
    44  			key = "-----BEGIN PUBLIC KEY-----\n" + key + "\n-----END PUBLIC KEY-----"
    45  		}
    46  
    47  		jwk, err := pemToJWK(key)
    48  		if err != nil {
    49  			return err
    50  		}
    51  
    52  		o.jwk = jwk
    53  		return nil
    54  	}
    55  }
    56  
    57  // WithCustomClaims allows to pass a type (e.g. struct), which will be populated with the token claims based on json tags.
    58  // For this option to work you must pass a pointer.
    59  func WithCustomClaims(customClaims interface{}) VerifyTokenOption {
    60  	return func(o *verifyTokenOptions) error {
    61  		o.customClaims = customClaims
    62  		return nil
    63  	}
    64  }
    65  
    66  func WithSatelliteDomain(isSatellite bool) VerifyTokenOption {
    67  	return func(o *verifyTokenOptions) error {
    68  		o.isSatellite = isSatellite
    69  		return nil
    70  	}
    71  }
    72  
    73  func WithProxyURL(proxyURL string) VerifyTokenOption {
    74  	return func(o *verifyTokenOptions) error {
    75  		o.proxyURL = proxyURL
    76  		return nil
    77  	}
    78  }
    79  
    80  func pemToJWK(key string) (*jose.JSONWebKey, error) {
    81  	block, _ := pem.Decode([]byte(key))
    82  	if block == nil {
    83  		return nil, fmt.Errorf("invalid PEM-encoded block")
    84  	}
    85  
    86  	if block.Type != "PUBLIC KEY" {
    87  		return nil, fmt.Errorf("invalid key type, expected a public key")
    88  	}
    89  
    90  	rsaPublicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
    91  	if err != nil {
    92  		return nil, fmt.Errorf("failed to parse public key: %v", err)
    93  	}
    94  
    95  	return &jose.JSONWebKey{Key: rsaPublicKey, Algorithm: "RS256"}, nil
    96  }