Skip to content

Commit

Permalink
Merge branch '0.18' into remove-combination-recipe/base
Browse files Browse the repository at this point in the history
  • Loading branch information
rishabhpoddar committed Apr 30, 2024
2 parents b9b22b7 + 57c6201 commit dd6e54a
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 22 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

## [0.18.0] - 2024-04-30

### Changes
- `session.CreateNewSession` now defaults to the value of the `st-auth-mode` header (if available) if the configured `config.GetTokenTransferMethod` returns `any`.
- Enable smooth switching between `useDynamicAccessTokenSigningKey` settings by allowing refresh calls to change the signing key type of a session.

### Breaking changes
- Make session required during signout.

## Breaking change

Expand Down
6 changes: 3 additions & 3 deletions recipe/emailpassword/authFlow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,7 @@ func TestDefaultSignoutRouteRevokesSession(t *testing.T) {
assert.Equal(t, "", cookieData1["refreshTokenDomain"])
}

func TestCallingTheAPIwithoutSessionShouldReturnOk(t *testing.T) {
func TestCallingTheAPIwithoutSessionShouldReturnUnauthorized(t *testing.T) {
configValue := supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "http://localhost:8080",
Expand Down Expand Up @@ -1550,8 +1550,8 @@ func TestCallingTheAPIwithoutSessionShouldReturnOk(t *testing.T) {
t.Error(err.Error())
}

assert.Equal(t, 200, res.StatusCode)
assert.Equal(t, "OK", data["status"])
assert.Equal(t, http.StatusUnauthorized, res.StatusCode)
assert.Empty(t, data["status"])
assert.Nil(t, req.Header["Cookie"])
}

Expand Down
44 changes: 36 additions & 8 deletions recipe/emailpassword/authMode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,43 @@ func TestWithGetTokenTransferMethodProvidedCreateNewSessionWithShouldUseHeaderIf
defer testServer.Close()
setupRoutesForTest(t, mux)

resp := createNewSession(t, testServer.URL, nil, nil, nil, nil)
t.Run("no st-auth-mode", func(t *testing.T) {
resp := createNewSession(t, testServer.URL, nil, nil, nil, nil)

assert.Equal(t, resp["sAccessToken"], "-not-present-")
assert.Equal(t, resp["sRefreshToken"], "-not-present-")
assert.Equal(t, resp["antiCsrf"], "-not-present-")
assert.NotEmpty(t, resp["accessTokenFromHeader"])
assert.NotEqual(t, resp["accessTokenFromHeader"], "-not-present-")
assert.NotEmpty(t, resp["refreshTokenFromHeader"])
assert.NotEqual(t, resp["refreshTokenFromHeader"], "-not-present-")
})

assert.Equal(t, resp["sAccessToken"], "-not-present-")
assert.Equal(t, resp["sRefreshToken"], "-not-present-")
assert.Equal(t, resp["antiCsrf"], "-not-present-")
assert.NotEmpty(t, resp["accessTokenFromHeader"])
assert.NotEqual(t, resp["accessTokenFromHeader"], "-not-present-")
assert.NotEmpty(t, resp["refreshTokenFromHeader"])
assert.NotEqual(t, resp["refreshTokenFromHeader"], "-not-present-")
t.Run("st-auth-mode is cookie", func(t *testing.T) {
authMode := string(sessmodels.CookieTransferMethod)
resp := createNewSession(t, testServer.URL, &authMode, nil, nil, nil)

assert.NotEqual(t, resp["sAccessToken"], "-not-present-")
assert.NotEqual(t, resp["sRefreshToken"], "-not-present-")
assert.NotEqual(t, resp["antiCsrf"], "-not-present-")
assert.NotEmpty(t, resp["accessTokenFromHeader"])
assert.Equal(t, resp["accessTokenFromHeader"], "-not-present-")
assert.NotEmpty(t, resp["refreshTokenFromHeader"])
assert.Equal(t, resp["refreshTokenFromHeader"], "-not-present-")
})

t.Run("st-auth-mode is header", func(t *testing.T) {
authMode := string(sessmodels.HeaderTransferMethod)
resp := createNewSession(t, testServer.URL, &authMode, nil, nil, nil)

assert.Equal(t, resp["sAccessToken"], "-not-present-")
assert.Equal(t, resp["sRefreshToken"], "-not-present-")
assert.Equal(t, resp["antiCsrf"], "-not-present-")
assert.NotEmpty(t, resp["accessTokenFromHeader"])
assert.NotEqual(t, resp["accessTokenFromHeader"], "-not-present-")
assert.NotEmpty(t, resp["refreshTokenFromHeader"])
assert.NotEqual(t, resp["refreshTokenFromHeader"], "-not-present-")
})
}

func TestWithGetTokenTransferMethodProvidedCreateNewSessionWithShouldUseHeaderIfMethodReturnsHeader(t *testing.T) {
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
85 changes: 85 additions & 0 deletions recipe/session/sessionHandlingFuncsWithoutReq_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package session

import (
"errors"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -472,3 +473,87 @@ func TestRefreshShouldReturnErrorForNonTokens(t *testing.T) {
assert.NotNil(t, err2)
assert.True(t, errors.As(err2, &sessionError.UnauthorizedError{}))
}

func TestUseDynamicAccessTokenSigningKey(t *testing.T) {
useDynamicAccessTokenSigningKey := 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: &useDynamicAccessTokenSigningKey,
}),
},
}
BeforeEach()
unittesting.StartUpST("localhost", "8080")
defer AfterEach()

checkAccessTokenSigningKeyType := func(t *testing.T, tokens sessmodels.SessionTokens, isDynamic bool) {
t.Helper()

info, err := ParseJWTWithoutSignatureVerification(tokens.AccessToken)
assert.NoError(t, err)

if isDynamic {
assert.True(t, strings.HasPrefix(*info.KID, "d-"))
} else {
assert.True(t, strings.HasPrefix(*info.KID, "s-"))
}
}

err := supertokens.Init(configValue)
assert.NoError(t, err)

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

assert.NoError(t, err)

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

resetAll()

// here we change to false
useDynamicAccessTokenSigningKey = false
err = supertokens.Init(configValue)
assert.NoError(t, err)

t.Run("should throw when verifying", func(t *testing.T) {
_, err = GetSessionWithoutRequestResponse(tokens.AccessToken, tokens.AntiCsrfToken, nil)
assert.Equal(t, err.Error(), "The access token doesn't match the useDynamicAccessTokenSigningKey setting")
})

t.Run("should work after refresh", func(t *testing.T) {
disableAntiCsrf := true
refreshedSession, err := RefreshSessionWithoutRequestResponse(*tokens.RefreshToken, &disableAntiCsrf, tokens.AntiCsrfToken)
assert.NoError(t, err)

tokensAfterRefresh := refreshedSession.GetAllSessionTokensDangerously()
assert.True(t, tokensAfterRefresh.AccessAndFrontendTokenUpdated)
checkAccessTokenSigningKeyType(t, tokensAfterRefresh, false)

verifiedSession, err := GetSessionWithoutRequestResponse(tokensAfterRefresh.AccessToken, tokensAfterRefresh.AntiCsrfToken, nil)
assert.NoError(t, err)

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

verifiedSession2, err := GetSessionWithoutRequestResponse(tokensAfterVerify.AccessToken, tokensAfterVerify.AntiCsrfToken, nil)
assert.NoError(t, err)

tokensAfterVerify2 := verifiedSession2.GetAllSessionTokensDangerously()
assert.False(t, tokensAfterVerify2.AccessAndFrontendTokenUpdated)
})
}
7 changes: 6 additions & 1 deletion recipe/session/sessionRequestFunctions.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ func CreateNewSessionInRequest(req *http.Request, res http.ResponseWriter, tenan

outputTokenTransferMethod := config.GetTokenTransferMethod(req, true, userContext)
if outputTokenTransferMethod == sessmodels.AnyTransferMethod {
outputTokenTransferMethod = sessmodels.HeaderTransferMethod
authMode := GetAuthmodeFromHeader(req)
if authMode != nil && *authMode == sessmodels.CookieTransferMethod {
outputTokenTransferMethod = *authMode
} else {
outputTokenTransferMethod = sessmodels.HeaderTransferMethod
}
}

supertokens.LogDebugMessage(fmt.Sprintf("createNewSession: using transfer method %s", outputTokenTransferMethod))
Expand Down
4 changes: 2 additions & 2 deletions recipe/session/signout.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ func SignOutAPI(apiImplementation sessmodels.APIInterface, options sessmodels.AP
return nil
}

False := false
sessionRequired := true
sessionContainer, err := GetSessionFromRequest(options.Req, options.Res, options.Config, &sessmodels.VerifySessionOptions{
SessionRequired: &False,
SessionRequired: &sessionRequired,
OverrideGlobalClaimValidators: func(globalClaimValidators []claims.SessionClaimValidator, sessionContainer sessmodels.SessionContainer, userContext supertokens.UserContext) ([]claims.SessionClaimValidator, error) {
return []claims.SessionClaimValidator{}, nil
},
Expand Down
6 changes: 3 additions & 3 deletions recipe/thirdparty/signoutFeature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
"gopkg.in/h2non/gock.v1"
)

func TestThatCallingTheAPIwithoutASessionShouldReturnOk(t *testing.T) {
func TestThatCallingTheAPIwithoutASessionShouldReturnUnauthorized(t *testing.T) {
configValue := supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "http://localhost:8080",
Expand Down Expand Up @@ -80,7 +80,7 @@ func TestThatCallingTheAPIwithoutASessionShouldReturnOk(t *testing.T) {
if err != nil {
t.Error(err.Error())
}
assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)

dataInBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
Expand All @@ -94,7 +94,7 @@ func TestThatCallingTheAPIwithoutASessionShouldReturnOk(t *testing.T) {
t.Error(err.Error())
}

assert.Equal(t, "OK", response["status"])
assert.Empty(t, response["status"])

assert.Equal(t, 0, len(resp.Cookies()))
}
Expand Down
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.18.0"

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

0 comments on commit dd6e54a

Please sign in to comment.