Skip to content

Commit

Permalink
Add AccessKeyLoginOptions (including customClaims) for ExchangeAccess…
Browse files Browse the repository at this point in the history
…Key API
  • Loading branch information
guyp-descope committed Feb 22, 2024
1 parent d6d2a61 commit f27c2d6
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 10 deletions.
4 changes: 2 additions & 2 deletions descope/internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ func (auth *authenticationService) validateAndRefreshSessionWithTokens(ctx conte
return false, nil, err
}

func (auth *authenticationService) ExchangeAccessKey(ctx context.Context, accessKey string) (success bool, SessionToken *descope.Token, err error) {
httpResponse, err := auth.client.DoPostRequest(ctx, api.Routes.ExchangeAccessKey(), nil, &api.HTTPRequest{}, accessKey)
func (auth *authenticationService) ExchangeAccessKey(ctx context.Context, accessKey string, loginOptions *descope.AccessKeyLoginOptions) (success bool, SessionToken *descope.Token, err error) {
httpResponse, err := auth.client.DoPostRequest(ctx, api.Routes.ExchangeAccessKey(), newExchangeAccessKeyBody(loginOptions), &api.HTTPRequest{}, accessKey)
if err != nil {
logger.LogError("Failed to exchange access key", err)
return false, nil, err
Expand Down
36 changes: 32 additions & 4 deletions descope/internal/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/descope/go-sdk/descope"
"github.com/descope/go-sdk/descope/api"
"github.com/descope/go-sdk/descope/internal/utils"
"github.com/descope/go-sdk/descope/tests/helpers"
"github.com/descope/go-sdk/descope/tests/mocks"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -857,7 +858,34 @@ func TestExchangeAccessKey(t *testing.T) {
a, err := newTestAuth(nil, DoOk(nil))
require.NoError(t, err)

ok, token, err := a.ExchangeAccessKey(context.Background(), "foo")
ok, token, err := a.ExchangeAccessKey(context.Background(), "foo", nil)
require.NoError(t, err)
require.True(t, ok)
require.NotNil(t, token)
}

func TestExchangeAccessKeyWithLoginOptions(t *testing.T) {
response := map[string]any{}
err := utils.Unmarshal([]byte(mockAuthSessionBody), &response)
a, err := newTestAuth(nil, helpers.DoOkWithBody(func(r *http.Request) {
req := map[string]any{}
require.NoError(t, helpers.ReadBody(r, &req))
rlo, found := req["loginOptions"]
require.True(t, found)
cc, found := rlo.(map[string]any)["customClaims"]
require.True(t, found)
customClaims, ok := cc.(map[string]any)
require.True(t, ok)
d, found := customClaims["k1"]
require.True(t, found)
require.EqualValues(t, "v1", d)
}, response))

loginOptions := &descope.AccessKeyLoginOptions{
CustomClaims: map[string]any{"k1": "v1"},
}

ok, token, err := a.ExchangeAccessKey(context.Background(), "foo", loginOptions)
require.NoError(t, err)
require.True(t, ok)
require.NotNil(t, token)
Expand All @@ -867,7 +895,7 @@ func TestExchangeAccessKeyBadRequest(t *testing.T) {
a, err := newTestAuth(nil, DoBadRequest(nil))
require.NoError(t, err)

ok, token, err := a.ExchangeAccessKey(context.Background(), "foo")
ok, token, err := a.ExchangeAccessKey(context.Background(), "foo", nil)
require.ErrorIs(t, err, descope.ErrBadRequest)
require.False(t, ok)
require.Nil(t, token)
Expand All @@ -877,7 +905,7 @@ func TestExchangeAccessKeyEmptyResponse(t *testing.T) {
a, err := newTestAuth(nil, DoOkWithBody(nil, ""))
require.NoError(t, err)

ok, token, err := a.ExchangeAccessKey(context.Background(), "foo")
ok, token, err := a.ExchangeAccessKey(context.Background(), "foo", nil)
require.ErrorIs(t, err, descope.ErrUnexpectedResponse)
require.False(t, ok)
require.Nil(t, token)
Expand All @@ -888,7 +916,7 @@ func TestExchangeAccessKeyInvalidResponse(t *testing.T) {
a, err := newTestAuth(nil, DoOkWithBody(nil, expectedResponse))
require.NoError(t, err)

ok, token, err := a.ExchangeAccessKey(context.Background(), "foo")
ok, token, err := a.ExchangeAccessKey(context.Background(), "foo", nil)
require.ErrorIs(t, err, descope.ErrUnexpectedResponse)
require.False(t, ok)
require.Nil(t, token)
Expand Down
8 changes: 8 additions & 0 deletions descope/internal/auth/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ func newExchangeTokenBody(code string) *exchangeTokenBody {
return &exchangeTokenBody{Code: code}
}

type exchangeAccessKeyBody struct {
LoginOptions *descope.AccessKeyLoginOptions `json:"loginOptions,omitempty"`
}

func newExchangeAccessKeyBody(loginOptions *descope.AccessKeyLoginOptions) *exchangeAccessKeyBody {
return &exchangeAccessKeyBody{LoginOptions: loginOptions}
}

const (
claimAttributeName = "drn"
claimPermissions = "permissions"
Expand Down
2 changes: 1 addition & 1 deletion descope/sdk/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ type Authentication interface {
ValidateAndRefreshSessionWithTokens(ctx context.Context, sessionToken, refreshToken string) (bool, *descope.Token, error)

// ExchangeAccessKey - Use to exchange an access key for a session token.
ExchangeAccessKey(ctx context.Context, accessKey string) (bool, *descope.Token, error)
ExchangeAccessKey(ctx context.Context, accessKey string, loginOptions *descope.AccessKeyLoginOptions) (bool, *descope.Token, error)

// ValidatePermissions - Use to ensure that a validated session token has been granted
// the specified permissions.
Expand Down
6 changes: 3 additions & 3 deletions descope/tests/mocks/auth/authenticationmock.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ type MockSession struct {
RefreshSessionResponseArray []*descope.Token
RefreshSessionResponseCounter int

ExchangeAccessKeyAssert func(accessKey string)
ExchangeAccessKeyAssert func(accessKey string, loginOptions *descope.AccessKeyLoginOptions)
ExchangeAccessKeyError error
ExchangeAccessKeyResponse *descope.Token
ExchangeAccessKeyResponseFailure bool
Expand Down Expand Up @@ -702,9 +702,9 @@ func (m *MockSession) ValidateAndRefreshSessionWithTokens(_ context.Context, ses
return !m.ValidateAndRefreshSessionTokensResponseFailure, m.ValidateAndRefreshSessionTokensResponse, m.ValidateAndRefreshSessionTokensError
}

func (m *MockSession) ExchangeAccessKey(_ context.Context, accessKey string) (bool, *descope.Token, error) {
func (m *MockSession) ExchangeAccessKey(_ context.Context, accessKey string, loginOptions *descope.AccessKeyLoginOptions) (bool, *descope.Token, error) {
if m.ExchangeAccessKeyAssert != nil {
m.ExchangeAccessKeyAssert(accessKey)
m.ExchangeAccessKeyAssert(accessKey, loginOptions)
}
return !m.ExchangeAccessKeyResponseFailure, m.ExchangeAccessKeyResponse, m.ExchangeAccessKeyError
}
Expand Down
4 changes: 4 additions & 0 deletions descope/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ func (lo *LoginOptions) IsJWTRequired() bool {
return lo != nil && (lo.Stepup || lo.MFA)
}

type AccessKeyLoginOptions struct {
CustomClaims map[string]interface{} `json:"customClaims,omitempty"`
}

type SignUpOptions struct {
CustomClaims map[string]interface{} `json:"customClaims,omitempty"`
TemplateOptions map[string]string `json:"templateOptions,omitempty"` // for providing messaging template options (templates that are being sent via email / text message)
Expand Down

0 comments on commit f27c2d6

Please sign in to comment.