@@ -22,6 +22,7 @@ func TestSessionStateSerialization(t *testing.T) {
2222 Email: "user@domain.com",
2323 AccessToken: "token1234",
2424 IDToken: "rawtoken1234",
25+ CreatedAt: time.Now(),
2526 ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
2627 RefreshToken: "refresh4321",
2728 }
@@ -35,6 +36,7 @@ func TestSessionStateSerialization(t *testing.T) {
3536 assert.Equal(t, s.Email, ss.Email)
3637 assert.Equal(t, s.AccessToken, ss.AccessToken)
3738 assert.Equal(t, s.IDToken, ss.IDToken)
39+ assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
3840 assert.Equal(t, s.ExpiresOn.Unix(), ss.ExpiresOn.Unix())
3941 assert.Equal(t, s.RefreshToken, ss.RefreshToken)
4042
@@ -44,6 +46,7 @@ func TestSessionStateSerialization(t *testing.T) {
4446 assert.Equal(t, nil, err)
4547 assert.NotEqual(t, "user@domain.com", ss.User)
4648 assert.NotEqual(t, s.Email, ss.Email)
49+ assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
4750 assert.Equal(t, s.ExpiresOn.Unix(), ss.ExpiresOn.Unix())
4851 assert.NotEqual(t, s.AccessToken, ss.AccessToken)
4952 assert.NotEqual(t, s.IDToken, ss.IDToken)
@@ -59,6 +62,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
5962 User: "just-user",
6063 Email: "user@domain.com",
6164 AccessToken: "token1234",
65+ CreatedAt: time.Now(),
6266 ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
6367 RefreshToken: "refresh4321",
6468 }
@@ -71,6 +75,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
7175 assert.Equal(t, s.User, ss.User)
7276 assert.Equal(t, s.Email, ss.Email)
7377 assert.Equal(t, s.AccessToken, ss.AccessToken)
78+ assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
7479 assert.Equal(t, s.ExpiresOn.Unix(), ss.ExpiresOn.Unix())
7580 assert.Equal(t, s.RefreshToken, ss.RefreshToken)
7681
@@ -80,6 +85,7 @@ func TestSessionStateSerializationWithUser(t *testing.T) {
8085 assert.Equal(t, nil, err)
8186 assert.NotEqual(t, s.User, ss.User)
8287 assert.NotEqual(t, s.Email, ss.Email)
88+ assert.Equal(t, s.CreatedAt.Unix(), ss.CreatedAt.Unix())
8389 assert.Equal(t, s.ExpiresOn.Unix(), ss.ExpiresOn.Unix())
8490 assert.NotEqual(t, s.AccessToken, ss.AccessToken)
8591 assert.NotEqual(t, s.RefreshToken, ss.RefreshToken)
@@ -89,6 +95,7 @@ func TestSessionStateSerializationNoCipher(t *testing.T) {
8995 s := &sessions.SessionState{
9096 Email: "user@domain.com",
9197 AccessToken: "token1234",
98+ CreatedAt: time.Now(),
9299 ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
93100 RefreshToken: "refresh4321",
94101 }
@@ -109,6 +116,7 @@ func TestSessionStateSerializationNoCipherWithUser(t *testing.T) {
109116 User: "just-user",
110117 Email: "user@domain.com",
111118 AccessToken: "token1234",
119+ CreatedAt: time.Now(),
112120 ExpiresOn: time.Now().Add(time.Duration(1) * time.Hour),
113121 RefreshToken: "refresh4321",
114122 }
@@ -147,6 +155,7 @@ type testCase struct {
147155// Currently only tests without cipher here because we have no way to mock
148156// the random generator used in EncodeSessionState.
149157func TestEncodeSessionState(t *testing.T) {
158+ c := time.Now()
150159 e := time.Now().Add(time.Duration(1) * time.Hour)
151160
152161 testCases := []testCase{
@@ -163,6 +172,7 @@ func TestEncodeSessionState(t *testing.T) {
163172 User: "just-user",
164173 AccessToken: "token1234",
165174 IDToken: "rawtoken1234",
175+ CreatedAt: c,
166176 ExpiresOn: e,
167177 RefreshToken: "refresh4321",
168178 },
@@ -185,6 +195,9 @@ func TestEncodeSessionState(t *testing.T) {
185195
186196// TestDecodeSessionState testssessions.DecodeSessionState with the test vector
187197func TestDecodeSessionState(t *testing.T) {
198+ created := time.Now()
199+ createdJSON, _ := created.MarshalJSON()
200+ createdString := string(createdJSON)
188201 e := time.Now().Add(time.Duration(1) * time.Hour)
189202 eJSON, _ := e.MarshalJSON()
190203 eString := string(eJSON)
@@ -219,7 +232,7 @@ func TestDecodeSessionState(t *testing.T) {
219232 Email: "user@domain.com",
220233 User: "just-user",
221234 },
222− Encoded: fmt.Sprintf(`{"Email":"user@domain.com","User":"just-user","AccessToken":"I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==","IDToken":"xojNdyyjB1HgYWh6XMtXY/Ph5eCVxa1cNsklJw==","RefreshToken":"qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K","ExpiresOn":%s}`, eString),
235+ Encoded: fmt.Sprintf(`{"Email":"user@domain.com","User":"just-user","AccessToken":"I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==","IDToken":"xojNdyyjB1HgYWh6XMtXY/Ph5eCVxa1cNsklJw==","RefreshToken":"qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K","CreatedAt":%s,"ExpiresOn":%s}`, createdString, eString),
223236 },
224237 {
225238 SessionState: sessions.SessionState{
@@ -227,10 +240,11 @@ func TestDecodeSessionState(t *testing.T) {
227240 User: "just-user",
228241 AccessToken: "token1234",
229242 IDToken: "rawtoken1234",
243+ CreatedAt: created,
230244 ExpiresOn: e,
231245 RefreshToken: "refresh4321",
232246 },
233− Encoded: fmt.Sprintf(`{"Email":"FsKKYrTWZWrxSOAqA/fTNAUZS5QWCqOBjuAbBlbVOw==","User":"rT6JP3dxQhxUhkWrrd7yt6c1mDVyQCVVxw==","AccessToken":"I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==","IDToken":"xojNdyyjB1HgYWh6XMtXY/Ph5eCVxa1cNsklJw==","RefreshToken":"qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K","ExpiresOn":%s}`, eString),
247+ Encoded: fmt.Sprintf(`{"Email":"FsKKYrTWZWrxSOAqA/fTNAUZS5QWCqOBjuAbBlbVOw==","User":"rT6JP3dxQhxUhkWrrd7yt6c1mDVyQCVVxw==","AccessToken":"I6s+ml+/MldBMgHIiC35BTKTh57skGX24w==","IDToken":"xojNdyyjB1HgYWh6XMtXY/Ph5eCVxa1cNsklJw==","RefreshToken":"qEX0x6RmASxo4dhlBG6YuRs9Syn/e9sHu/+K","CreatedAt":%s,"ExpiresOn":%s}`, createdString, eString),
234248 Cipher: c,
235249 },
236250 {
@@ -316,3 +330,14 @@ func TestDecodeSessionState(t *testing.T) {
316330 }
317331 }
318332}
333+
334+func TestSessionStateAge(t *testing.T) {
335+ ss := &sessions.SessionState{}
336+
337+ // Created at unset so should be 0
338+ assert.Equal(t, time.Duration(0), ss.Age())
339+
340+ // Set CreatedAt to 1 hour ago
341+ ss.CreatedAt = time.Now().Add(-1 * time.Hour)
342+ assert.Equal(t, time.Hour, ss.Age().Round(time.Minute))
343+}