Skip to content

Commit

Permalink
fix: smooth switching between useDynamicAccessTokenSigningKey
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Apr 4, 2024
1 parent f581384 commit 7f865fd
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

## [0.17.6] - 2024-04-04

- Enable smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to change the signing key type of a session

## [0.17.5] - 2024-03-14

- Adds a type uint64 to the `accessTokenCookiesExpiryDurationMillis` local variable in `recipe/session/utils.go`. It also removes the redundant `uint64` type forcing needed because of the untyped variable.
- Fixes the passing of `tenantId` in `getAllSessionHandlesForUser` and `revokeAllSessionsForUser` based on `fetchAcrossAllTenants` and `revokeAcrossAllTenants` inputs respectively.
- Updated fake email generation
Expand Down
2 changes: 1 addition & 1 deletion recipe/session/recipeImplementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ func MakeRecipeImplementation(querier supertokens.Querier, config sessmodels.Typ

supertokens.LogDebugMessage("refreshSession: Started")

response, err := refreshSessionHelper(config, querier, refreshToken, antiCsrfToken, disableAntiCsrf, userContext)
response, err := refreshSessionHelper(config, querier, refreshToken, antiCsrfToken, disableAntiCsrf, config.UseDynamicAccessTokenSigningKey, userContext)
if err != nil {
return nil, err
}
Expand Down
7 changes: 4 additions & 3 deletions recipe/session/sessionFunctions.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,11 @@ func getSessionInformationHelper(querier supertokens.Querier, sessionHandle stri
return nil, nil
}

func refreshSessionHelper(config sessmodels.TypeNormalisedInput, querier supertokens.Querier, refreshToken string, antiCsrfToken *string, disableAntiCsrf bool, userContext supertokens.UserContext) (sessmodels.CreateOrRefreshAPIResponse, error) {
func refreshSessionHelper(config sessmodels.TypeNormalisedInput, querier supertokens.Querier, refreshToken string, antiCsrfToken *string, disableAntiCsrf bool, useDynamicAccessTokenSigningKey bool, userContext supertokens.UserContext) (sessmodels.CreateOrRefreshAPIResponse, error) {
requestBody := map[string]interface{}{
"refreshToken": refreshToken,
"enableAntiCsrf": !disableAntiCsrf && config.AntiCsrfFunctionOrString.StrValue == AntiCSRF_VIA_TOKEN,
"refreshToken": refreshToken,
"enableAntiCsrf": !disableAntiCsrf && config.AntiCsrfFunctionOrString.StrValue == AntiCSRF_VIA_TOKEN,
"useDynamicSigningKey": useDynamicAccessTokenSigningKey,
}
if antiCsrfToken != nil {
requestBody["antiCsrfToken"] = *antiCsrfToken
Expand Down
162 changes: 162 additions & 0 deletions recipe/session/switchingUseDynamicAccessTokenSigningKey_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package session

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
"github.com/supertokens/supertokens-golang/supertokens"
"github.com/supertokens/supertokens-golang/test/unittesting"
)

func TestUseDynamicAccessTokenSigningKeySwitchingFromTrueToFalse(t *testing.T) {
True := true
configValue := supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "http://localhost:8080",
},
AppInfo: supertokens.AppInfo{
AppName: "SuperTokens",
WebsiteDomain: "supertokens.io",
APIDomain: "api.supertokens.io",
},
RecipeList: []supertokens.Recipe{
Init(&sessmodels.TypeInput{
UseDynamicAccessTokenSigningKey: &True,
}),
},
}
BeforeEach()
unittesting.StartUpST("localhost", "8080")
defer AfterEach()
err := supertokens.Init(configValue)
if err != nil {
t.Error(err.Error())
}

res, err := CreateNewSessionWithoutRequestResponse("public", "test-user-id", map[string]interface{}{
"tokenProp": true,
}, map[string]interface{}{
"dbProp": true,
}, nil)
assert.Nil(t, err)

tokens := res.GetAllSessionTokensDangerously()
checkAccessTokenSigningKeyType(t, tokens, true)

resetAll()
False := false
configValue = supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "http://localhost:8080",
},
AppInfo: supertokens.AppInfo{
AppName: "SuperTokens",
WebsiteDomain: "supertokens.io",
APIDomain: "api.supertokens.io",
},
RecipeList: []supertokens.Recipe{
Init(&sessmodels.TypeInput{
UseDynamicAccessTokenSigningKey: &False,
}),
},
}

err = supertokens.Init(configValue)
if err != nil {
t.Error(err.Error())
}

_, err = GetSessionWithoutRequestResponse(tokens.AccessToken, tokens.AntiCsrfToken, nil)
assert.NotNil(t, err)

assert.Equal(t, "The access token doesn't match the useDynamicAccessTokenSigningKey setting", err.Error())
}

func TestUseDynamicAccessTokenSigningKeySwitchingFromTrueToFalseShouldWorkAfterRefresh(t *testing.T) {
True := true
configValue := supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "http://localhost:8080",
},
AppInfo: supertokens.AppInfo{
AppName: "SuperTokens",
WebsiteDomain: "supertokens.io",
APIDomain: "api.supertokens.io",
},
RecipeList: []supertokens.Recipe{
Init(&sessmodels.TypeInput{
UseDynamicAccessTokenSigningKey: &True,
}),
},
}
BeforeEach()
unittesting.StartUpST("localhost", "8080")
defer AfterEach()
err := supertokens.Init(configValue)
if err != nil {
t.Error(err.Error())
}

res, err := CreateNewSessionWithoutRequestResponse("public", "test-user-id", map[string]interface{}{
"tokenProp": true,
}, map[string]interface{}{
"dbProp": true,
}, nil)
assert.Nil(t, err)

tokens := res.GetAllSessionTokensDangerously()
checkAccessTokenSigningKeyType(t, tokens, true)

resetAll()
False := false
configValue = supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "http://localhost:8080",
},
AppInfo: supertokens.AppInfo{
AppName: "SuperTokens",
WebsiteDomain: "supertokens.io",
APIDomain: "api.supertokens.io",
},
RecipeList: []supertokens.Recipe{
Init(&sessmodels.TypeInput{
UseDynamicAccessTokenSigningKey: &False,
}),
},
}

err = supertokens.Init(configValue)
if err != nil {
t.Error(err.Error())
}

refreshedSession, err := RefreshSessionWithoutRequestResponse(*tokens.RefreshToken, nil, tokens.AntiCsrfToken)
assert.Nil(t, err)

tokens = refreshedSession.GetAllSessionTokensDangerously()
checkAccessTokenSigningKeyType(t, tokens, false)

verifiedSession, err := GetSessionWithoutRequestResponse(tokens.AccessToken, tokens.AntiCsrfToken, nil)
assert.Nil(t, err)

tokensAfterVerify := verifiedSession.GetAllSessionTokensDangerously()
assert.True(t, tokensAfterVerify.AccessAndFrontendTokenUpdated)

verified2Session, err := GetSessionWithoutRequestResponse(tokensAfterVerify.AccessToken, tokensAfterVerify.AntiCsrfToken, nil)
assert.Nil(t, err)

tokensAfterVerify2 := verified2Session.GetAllSessionTokensDangerously()
assert.False(t, tokensAfterVerify2.AccessAndFrontendTokenUpdated)
}

func checkAccessTokenSigningKeyType(t *testing.T, tokens sessmodels.SessionTokens, isDynamic bool) {
info, err := ParseJWTWithoutSignatureVerification(tokens.AccessToken)
assert.Nil(t, err)
if isDynamic {
assert.True(t, strings.HasPrefix(*info.KID, "d-"))
} else {
assert.True(t, strings.HasPrefix(*info.KID, "s-"))
}
}
2 changes: 1 addition & 1 deletion supertokens/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
)

// VERSION current version of the lib
const VERSION = "0.17.5"
const VERSION = "0.17.6"

var (
cdiSupported = []string{"3.0"}
Expand Down

0 comments on commit 7f865fd

Please sign in to comment.