credentials/jwt.go (53 lines of code) (raw):

package credentials import ( "fmt" "io" "net/url" "strings" "time" "github.com/golang-jwt/jwt/v5" ) const ( JwtExpiration = 3 * time.Minute ) type jwtProvider struct { creds JwtCredentials now func() time.Time // Function to get the current time, useful for testing } func (provider *jwtProvider) Retrieve() (io.Reader, error) { expirationTime := provider.GetAppropriateExpirationTime() tokenString, err := provider.BuildClaimsToken(expirationTime, provider.creds.URL, provider.creds.ClientId, provider.creds.ClientUsername) if err != nil { return nil, fmt.Errorf("jwtProvider.Retrieve() error: %w", err) } form := url.Values{} form.Add("grant_type", string(jwtGrantType)) form.Add("assertion", tokenString) return strings.NewReader(form.Encode()), nil } func (provider *jwtProvider) URL() string { return provider.creds.URL } func (provider *jwtProvider) GetAppropriateExpirationTime() time.Time { if provider.now != nil { return provider.now().Add(JwtExpiration) } return time.Now().Add(JwtExpiration) } func (provider *jwtProvider) BuildClaimsToken(expirationTime time.Time, url string, clientId string, clientUsername string) (string, error) { claims := jwt.MapClaims{ "iss": clientId, "sub": clientUsername, "aud": url, "exp": expirationTime.Unix(), } token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) if provider.creds.ClientKey == nil { return "", fmt.Errorf("jwtProvider.BuildClaimsToken() error: clientKey is nil") } tokenString, err := token.SignedString(provider.creds.ClientKey) if err != nil { return "", fmt.Errorf("jwtProvider.BuildClaimsToken() error: failed to sign token: %w", err) } return tokenString, nil }