Skip to content

Commit 54b9735

Browse files
committed
fix: adds updating of session claims in email verification token generation API
1 parent 1a8e10a commit 54b9735

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [unreleased]
99
- Fixes go fiber to handle handler chaining correctly with verifySession.
1010
- Added test to check JWT contains updated value when MergeIntoAccessTokenPayload is called.
11+
- Adds updating of session claims in email verification token generation API in case the session claims are outdated.
1112

1213
## [0.9.7] - 2022-10-20
1314
- Updated Frontend integration test server for angular tests
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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+
52+
mux := http.NewServeMux()
53+
testServer := httptest.NewServer(supertokens.Middleware(mux))
54+
defer testServer.Close()
55+
56+
resp, err := unittesting.SignupRequest("[email protected]", "testPass123", testServer.URL)
57+
assert.NoError(t, err)
58+
59+
assert.Equal(t, 200, resp.StatusCode)
60+
bodyBytes, err := ioutil.ReadAll(resp.Body)
61+
assert.NoError(t, err)
62+
63+
bodyObj := map[string]interface{}{}
64+
err = json.Unmarshal(bodyBytes, &bodyObj)
65+
assert.NoError(t, err)
66+
67+
userId := bodyObj["user"].(map[string]interface{})["id"].(string)
68+
infoFromResponse := unittesting.ExtractInfoFromResponse(resp)
69+
antiCsrf := infoFromResponse["antiCsrf"]
70+
71+
token, err := emailverification.CreateEmailVerificationToken(userId, nil)
72+
assert.NoError(t, err)
73+
_, err = emailverification.VerifyEmailUsingToken(token.OK.Token)
74+
assert.NoError(t, err)
75+
76+
resp, err = unittesting.EmailVerifyTokenRequest(
77+
testServer.URL,
78+
userId,
79+
infoFromResponse["sAccessToken"],
80+
infoFromResponse["sIdRefreshToken"],
81+
antiCsrf,
82+
)
83+
assert.NoError(t, err)
84+
assert.Equal(t, 200, resp.StatusCode)
85+
86+
infoFromResponse = unittesting.ExtractInfoFromResponse(resp)
87+
b64Bytes, err := base64.StdEncoding.DecodeString(infoFromResponse["frontToken"])
88+
assert.NoError(t, err)
89+
frontendInfo := map[string]interface{}{}
90+
err = json.Unmarshal(b64Bytes, &frontendInfo)
91+
assert.NoError(t, err)
92+
93+
val := frontendInfo["up"].(map[string]interface{})["st-ev"].(map[string]interface{})["v"].(bool)
94+
fmt.Println(val)
95+
assert.True(t, frontendInfo["up"].(map[string]interface{})["st-ev"].(map[string]interface{})["v"].(bool))
96+
97+
// Calling again should not modify access token
98+
resp, err = unittesting.EmailVerifyTokenRequest(
99+
testServer.URL,
100+
userId,
101+
infoFromResponse["sAccessToken"],
102+
infoFromResponse["sIdRefreshToken"],
103+
antiCsrf,
104+
)
105+
assert.NoError(t, err)
106+
assert.Equal(t, 200, resp.StatusCode)
107+
108+
infoFromResponse2 := unittesting.ExtractInfoFromResponse(resp)
109+
assert.Empty(t, infoFromResponse2["frontToken"])
110+
111+
// now we mark the email as unverified and try again
112+
emailverification.UnverifyEmail(userId, nil)
113+
resp, err = unittesting.EmailVerifyTokenRequest(
114+
testServer.URL,
115+
userId,
116+
infoFromResponse["sAccessToken"],
117+
infoFromResponse["sIdRefreshToken"],
118+
antiCsrf,
119+
)
120+
assert.NoError(t, err)
121+
assert.Equal(t, 200, resp.StatusCode)
122+
123+
infoFromResponse = unittesting.ExtractInfoFromResponse(resp)
124+
b64Bytes, err = base64.StdEncoding.DecodeString(infoFromResponse["frontToken"])
125+
assert.NoError(t, err)
126+
frontendInfo = map[string]interface{}{}
127+
err = json.Unmarshal(b64Bytes, &frontendInfo)
128+
assert.NoError(t, err)
129+
assert.False(t, frontendInfo["up"].(map[string]interface{})["st-ev"].(map[string]interface{})["v"].(bool))
130+
131+
// calling the API again should not modify the access token again
132+
resp, err = unittesting.EmailVerifyTokenRequest(
133+
testServer.URL,
134+
userId,
135+
infoFromResponse["sAccessToken"],
136+
infoFromResponse["sIdRefreshToken"],
137+
antiCsrf,
138+
)
139+
assert.NoError(t, err)
140+
assert.Equal(t, 200, resp.StatusCode)
141+
142+
infoFromResponse2 = unittesting.ExtractInfoFromResponse(resp)
143+
assert.Empty(t, infoFromResponse2["frontToken"])
144+
}

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,

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)