Skip to content

Commit 5700320

Browse files
Merge pull request #204 from supertokens/ev-session-claims-issue
fix: Adds updating of session claims in email verification token generation API in case the session claims are outdated
2 parents 1a8e10a + 8fc2506 commit 5700320

File tree

5 files changed

+169
-1
lines changed

5 files changed

+169
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [unreleased]
9+
10+
## [0.9.8] - 2022-11-16
911
- Fixes go fiber to handle handler chaining correctly with verifySession.
1012
- Added test to check JWT contains updated value when MergeIntoAccessTokenPayload is called.
13+
- Adds updating of session claims in email verification token generation API in case the session claims are outdated.
1114

1215
## [0.9.7] - 2022-10-20
1316
- Updated Frontend integration test server for angular tests
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package emailpassword
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/json"
6+
"fmt"
7+
"io/ioutil"
8+
"net/http"
9+
"net/http/httptest"
10+
"testing"
11+
12+
"github.com/stretchr/testify/assert"
13+
"github.com/supertokens/supertokens-golang/recipe/emailverification"
14+
"github.com/supertokens/supertokens-golang/recipe/emailverification/evmodels"
15+
"github.com/supertokens/supertokens-golang/recipe/session"
16+
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
17+
"github.com/supertokens/supertokens-golang/supertokens"
18+
"github.com/supertokens/supertokens-golang/test/unittesting"
19+
)
20+
21+
func TestEVGenerateUpdatesSessionClaims(t *testing.T) {
22+
antiCsrfConf := "VIA_TOKEN"
23+
configValue := supertokens.TypeInput{
24+
Supertokens: &supertokens.ConnectionInfo{
25+
ConnectionURI: "http://localhost:8080",
26+
},
27+
AppInfo: supertokens.AppInfo{
28+
APIDomain: "api.supertokens.io",
29+
AppName: "SuperTokens",
30+
WebsiteDomain: "supertokens.io",
31+
},
32+
RecipeList: []supertokens.Recipe{
33+
Init(nil),
34+
emailverification.Init(evmodels.TypeInput{
35+
Mode: evmodels.ModeOptional,
36+
CreateAndSendCustomEmail: func(user evmodels.User, emailVerificationURLWithToken string, userContext supertokens.UserContext) {},
37+
}),
38+
session.Init(&sessmodels.TypeInput{
39+
AntiCsrf: &antiCsrfConf,
40+
}),
41+
},
42+
}
43+
44+
BeforeEach()
45+
unittesting.StartUpST("localhost", "8080")
46+
defer AfterEach()
47+
err := supertokens.Init(configValue)
48+
if err != nil {
49+
t.Error(err.Error())
50+
}
51+
querier, err := supertokens.GetNewQuerierInstanceOrThrowError("")
52+
if err != nil {
53+
t.Error(err.Error())
54+
}
55+
cdiVersion, err := querier.GetQuerierAPIVersion()
56+
if err != nil {
57+
t.Error(err.Error())
58+
}
59+
if unittesting.MaxVersion("2.10", cdiVersion) != cdiVersion {
60+
return
61+
}
62+
63+
mux := http.NewServeMux()
64+
testServer := httptest.NewServer(supertokens.Middleware(mux))
65+
defer testServer.Close()
66+
67+
resp, err := unittesting.SignupRequest("[email protected]", "testPass123", testServer.URL)
68+
assert.NoError(t, err)
69+
70+
assert.Equal(t, 200, resp.StatusCode)
71+
bodyBytes, err := ioutil.ReadAll(resp.Body)
72+
assert.NoError(t, err)
73+
74+
bodyObj := map[string]interface{}{}
75+
err = json.Unmarshal(bodyBytes, &bodyObj)
76+
assert.NoError(t, err)
77+
78+
userId := bodyObj["user"].(map[string]interface{})["id"].(string)
79+
infoFromResponse := unittesting.ExtractInfoFromResponse(resp)
80+
antiCsrf := infoFromResponse["antiCsrf"]
81+
82+
token, err := emailverification.CreateEmailVerificationToken(userId, nil)
83+
assert.NoError(t, err)
84+
_, err = emailverification.VerifyEmailUsingToken(token.OK.Token)
85+
assert.NoError(t, err)
86+
87+
resp, err = unittesting.EmailVerifyTokenRequest(
88+
testServer.URL,
89+
userId,
90+
infoFromResponse["sAccessToken"],
91+
infoFromResponse["sIdRefreshToken"],
92+
antiCsrf,
93+
)
94+
assert.NoError(t, err)
95+
assert.Equal(t, 200, resp.StatusCode)
96+
97+
infoFromResponse = unittesting.ExtractInfoFromResponse(resp)
98+
b64Bytes, err := base64.StdEncoding.DecodeString(infoFromResponse["frontToken"])
99+
assert.NoError(t, err)
100+
frontendInfo := map[string]interface{}{}
101+
err = json.Unmarshal(b64Bytes, &frontendInfo)
102+
assert.NoError(t, err)
103+
104+
val := frontendInfo["up"].(map[string]interface{})["st-ev"].(map[string]interface{})["v"].(bool)
105+
fmt.Println(val)
106+
assert.True(t, frontendInfo["up"].(map[string]interface{})["st-ev"].(map[string]interface{})["v"].(bool))
107+
108+
// Calling again should not modify access token
109+
resp, err = unittesting.EmailVerifyTokenRequest(
110+
testServer.URL,
111+
userId,
112+
infoFromResponse["sAccessToken"],
113+
infoFromResponse["sIdRefreshToken"],
114+
antiCsrf,
115+
)
116+
assert.NoError(t, err)
117+
assert.Equal(t, 200, resp.StatusCode)
118+
119+
infoFromResponse2 := unittesting.ExtractInfoFromResponse(resp)
120+
assert.Empty(t, infoFromResponse2["frontToken"])
121+
122+
// now we mark the email as unverified and try again
123+
emailverification.UnverifyEmail(userId, nil)
124+
resp, err = unittesting.EmailVerifyTokenRequest(
125+
testServer.URL,
126+
userId,
127+
infoFromResponse["sAccessToken"],
128+
infoFromResponse["sIdRefreshToken"],
129+
antiCsrf,
130+
)
131+
assert.NoError(t, err)
132+
assert.Equal(t, 200, resp.StatusCode)
133+
134+
infoFromResponse = unittesting.ExtractInfoFromResponse(resp)
135+
b64Bytes, err = base64.StdEncoding.DecodeString(infoFromResponse["frontToken"])
136+
assert.NoError(t, err)
137+
frontendInfo = map[string]interface{}{}
138+
err = json.Unmarshal(b64Bytes, &frontendInfo)
139+
assert.NoError(t, err)
140+
assert.False(t, frontendInfo["up"].(map[string]interface{})["st-ev"].(map[string]interface{})["v"].(bool))
141+
142+
// calling the API again should not modify the access token again
143+
resp, err = unittesting.EmailVerifyTokenRequest(
144+
testServer.URL,
145+
userId,
146+
infoFromResponse["sAccessToken"],
147+
infoFromResponse["sIdRefreshToken"],
148+
antiCsrf,
149+
)
150+
assert.NoError(t, err)
151+
assert.Equal(t, 200, resp.StatusCode)
152+
153+
infoFromResponse2 = unittesting.ExtractInfoFromResponse(resp)
154+
assert.Empty(t, infoFromResponse2["frontToken"])
155+
}

recipe/emailverification/api/implementation.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,19 @@ func MakeAPIImplementation() evmodels.APIInterface {
102102
}
103103

104104
if response.EmailAlreadyVerifiedError != nil {
105+
if sessionContainer.GetClaimValue(evclaims.EmailVerificationClaim) != true {
106+
sessionContainer.FetchAndSetClaimWithContext(evclaims.EmailVerificationClaim, userContext)
107+
}
105108
supertokens.LogDebugMessage(fmt.Sprintf("Email verification email not sent to %s because it is already verified", email.OK.Email))
106109
return evmodels.GenerateEmailVerifyTokenPOSTResponse{
107110
EmailAlreadyVerifiedError: &struct{}{},
108111
}, nil
109112
}
110113

114+
if sessionContainer.GetClaimValue(evclaims.EmailVerificationClaim) != false {
115+
sessionContainer.FetchAndSetClaimWithContext(evclaims.EmailVerificationClaim, userContext)
116+
}
117+
111118
user := evmodels.User{
112119
ID: userID,
113120
Email: email.OK.Email,

supertokens/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const (
2121
)
2222

2323
// VERSION current version of the lib
24-
const VERSION = "0.9.7"
24+
const VERSION = "0.9.8"
2525

2626
var (
2727
cdiSupported = []string{"2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.15"}

test/unittesting/testingutils.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ func ExtractInfoFromResponse(res *http.Response) map[string]string {
258258
if len(antiCsrf) > 0 {
259259
antiCsrfVal = antiCsrf[0]
260260
}
261+
frontToken := res.Header.Get("front-token")
262+
261263
return map[string]string{
262264
"antiCsrf": antiCsrfVal,
263265
"sAccessToken": accessToken,
@@ -273,6 +275,7 @@ func ExtractInfoFromResponse(res *http.Response) map[string]string {
273275
"accessTokenExpiry": accessTokenExpiry,
274276
"accessTokenDomain": accessTokenDomain,
275277
"accessTokenHttpOnly": accessTokenHttpOnly,
278+
"frontToken": frontToken,
276279
}
277280
}
278281

0 commit comments

Comments
 (0)