diff --git a/pkg/token/static_token_provider.go b/pkg/token/static_token_provider.go index 0e28646..6c0b4eb 100644 --- a/pkg/token/static_token_provider.go +++ b/pkg/token/static_token_provider.go @@ -6,6 +6,7 @@ package token import ( "context" "sync" + "time" "emperror.dev/errors" "github.com/golang-jwt/jwt/v5" @@ -52,9 +53,15 @@ func (s *StaticIdentityTokenProvider) GetToken(ctx context.Context, opts ...opti return credential.Token{}, errors.WrapIf(err, "failed to get token expiration time") } + // exp is optional; a zero ExpiresAt means the token never expires. + var expiresAt time.Time + if exp != nil { + expiresAt = exp.Time + } + return credential.Token{ Token: t.Raw, - ExpiresAt: exp.Time, + ExpiresAt: expiresAt, }, nil } diff --git a/pkg/token/static_token_provider_test.go b/pkg/token/static_token_provider_test.go new file mode 100644 index 0000000..c8348b6 --- /dev/null +++ b/pkg/token/static_token_provider_test.go @@ -0,0 +1,69 @@ +// Copyright (c) 2026 Riptides Labs, Inc. +// SPDX-License-Identifier: MIT + +package token_test + +import ( + "testing" + "time" + + "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.riptides.io/tokenex/pkg/token" +) + +func newJWT(t *testing.T, claims jwt.MapClaims) string { + t.Helper() + + s, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte("test-key")) + require.NoError(t, err) + + return s +} + +func TestStaticIdentityTokenProvider_GetToken(t *testing.T) { + t.Parallel() + + exp := time.Now().Add(time.Hour) + + tests := []struct { + name string + token string + wantExpiresAt time.Time + wantErr bool + }{ + { + name: "with exp", + token: newJWT(t, jwt.MapClaims{"sub": "workload", "exp": exp.Unix()}), + wantExpiresAt: time.Unix(exp.Unix(), 0), + }, + { + name: "without exp never expires", + token: newJWT(t, jwt.MapClaims{"sub": "workload"}), + }, + { + name: "not a JWT", + token: "not-a-jwt", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + tok, err := token.NewStaticIdentityTokenProvider(tt.token).GetToken(t.Context()) + if tt.wantErr { + require.Error(t, err) + + return + } + + require.NoError(t, err) + assert.Equal(t, tt.token, tok.Token) + assert.True(t, tt.wantExpiresAt.Equal(tok.ExpiresAt), "ExpiresAt = %v, want %v", tok.ExpiresAt, tt.wantExpiresAt) + }) + } +}