Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions sdk/access_token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package sdk

import (
"context"
"net/http"
"testing"

"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/opentdf/platform/sdk/auth"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestAccessToken_ReturnsTokenFromSource(t *testing.T) {
s := &SDK{tokenSource: FakeAccessTokenSource{accessToken: "test-token"}}

tok, err := s.Auth().AccessToken(context.Background())
require.NoError(t, err)
assert.Equal(t, auth.AccessToken("test-token"), tok)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

func TestAccessToken_NoTokenSource(t *testing.T) {
s := &SDK{}

tok, err := s.Auth().AccessToken(context.Background())
require.ErrorIs(t, err, ErrNoAccessTokenSource)
assert.Empty(t, tok)
}

func TestAccessToken_EmptyToken(t *testing.T) {
s := &SDK{tokenSource: FakeAccessTokenSource{accessToken: ""}}

tok, err := s.Auth().AccessToken(context.Background())
require.ErrorIs(t, err, ErrAccessTokenInvalid)
assert.Empty(t, tok)
}

type recordCtxKey struct{}

// recordingTokenSource captures what AccessToken forwards to it so tests can assert
// the context and HTTP client are passed through. It records a context value rather
// than the context itself (avoiding a context.Context struct field) and the client
// pointer for identity comparison.
type recordingTokenSource struct {
token string
gotCtxValue any
gotClient *http.Client
}

func (r *recordingTokenSource) AccessToken(ctx context.Context, client *http.Client) (auth.AccessToken, error) {
r.gotCtxValue = ctx.Value(recordCtxKey{})
r.gotClient = client
return auth.AccessToken(r.token), nil
}

func (r *recordingTokenSource) MakeToken(func(jwk.Key) ([]byte, error)) ([]byte, error) {
return nil, nil
}

func TestAccessToken_ForwardsContextAndClient(t *testing.T) {
ctx := context.WithValue(context.Background(), recordCtxKey{}, "value")
client := &http.Client{}

rec := &recordingTokenSource{token: "test-token"}
s := &SDK{tokenSource: rec}
s.httpClient = client

tok, err := s.Auth().AccessToken(ctx)
require.NoError(t, err)
assert.Equal(t, auth.AccessToken("test-token"), tok)
assert.Equal(t, "value", rec.gotCtxValue, "context should be forwarded unchanged")
assert.Same(t, client, rec.gotClient, "http client should be forwarded unchanged")
}
34 changes: 34 additions & 0 deletions sdk/auth_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package sdk

import (
"context"

"github.com/opentdf/platform/sdk/auth"
)

// Auth returns an AuthClient for authentication-related operations.
func (s *SDK) Auth() *AuthClient {
return &AuthClient{sdk: s}
}

// AuthClient groups authentication operations for the SDK.
type AuthClient struct {
sdk *SDK
}

// AccessToken returns a valid access token for the SDK's configured credentials.
// It returns ErrNoAccessTokenSource if the SDK was created without credentials, and
// ErrAccessTokenInvalid if the token source returns an empty token.
func (a *AuthClient) AccessToken(ctx context.Context) (auth.AccessToken, error) {
if a.sdk.tokenSource == nil {
return "", ErrNoAccessTokenSource
}
token, err := a.sdk.tokenSource.AccessToken(ctx, a.sdk.httpClient)
if err != nil {
return "", err
}
if token == "" {
return "", ErrAccessTokenInvalid
}
return token, nil
}
1 change: 1 addition & 0 deletions sdk/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
ErrPlatformTokenEndpointNotFound = Error("token_endpoint not found in well-known idp configuration")
ErrPlatformEndpointNotFound = Error("platform_endpoint not found in well-known configuration")
ErrAccessTokenInvalid = Error("access token is invalid")
ErrNoAccessTokenSource = Error("no access token source configured; SDK was created without credentials")
ErrWellKnowConfigEmpty = Error("well-known configuration is empty")
ErrAttributeNotFound = Error("attribute not found")
)
Expand Down
Loading