Skip to content

Commit 4afd124

Browse files
authored
Merge pull request #19703 from mozilla/restore-verified-flag
task(auth): Restore session verified flag
2 parents 7e3e1e0 + f494fb3 commit 4afd124

File tree

4 files changed

+87
-12
lines changed

4 files changed

+87
-12
lines changed

packages/fxa-auth-server/docs/swagger/session-api.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,15 @@ const SESSION_REAUTH_POST = {
4343
Re-authenticate an existing session token. This is equivalent to calling \`/account/login\`, but it re-uses an existing session token rather than generating a new one, allowing the caller to maintain session state such as verification and device registration.
4444
4545
The response includes:
46-
- \`emailVerified\`: Whether the account's primary email address has been verified
47-
- \`sessionVerified\`: Whether the current session token has been verified
46+
- \`uid\`: Account id
47+
- \`keyFetchToken\`: Present if keys were requested.
4848
- \`verificationMethod\`: Present if verification is incomplete, e.g. \`email\`, \`email-2fa\`, \`email-otp\`, \`totp-2fa\`
4949
- \`verificationReason\`: Present if verification is incomplete, e.g. \`login\`, \`signup\`
50+
- \`emailVerified\`: Whether the account's primary email address has been verified
51+
- \`sessionVerified\`: Whether the current session token has been verified
52+
- \`authAt\`: Timestamp of authentication
53+
- \`metricsEnabled\`: Flag indicating if metrics are enabled on the session
54+
- \`verified\`: Deprecated! Use emailVerified and sessionVerified instead.
5055
`,
5156
],
5257
plugins: {
@@ -78,11 +83,15 @@ const SESSION_STATUS_GET = {
7883
7984
Returns a success response if the session token is valid. The response includes detailed information about the session and account state.
8085
81-
**Response details object:**
82-
- \`accountEmailVerified\`: Whether the account's primary email is verified
83-
- \`sessionVerificationMethod\`: The verification method used for the session (e.g., 'email-2fa', 'totp-2fa'), or null if not verified
84-
- \`sessionVerified\`: Whether the session token itself is verified (no pending token verification)
85-
- \`sessionVerificationMeetsMinimumAAL\`: Whether the session's Authentication Assurance Level (AAL) meets or exceeds the account's maximum AAL
86+
87+
**Response object:**
88+
- \`state\`: Describes the session's verification state.
89+
- \`uid\`: Account id
90+
- \`details.accountEmailVerified\`: Whether the account's primary email is verified
91+
- \`details.sessionVerificationMethod\`: The verification method used for the session (e.g., 'email-2fa', 'totp-2fa'), or null if not verified
92+
- \`details.sessionVerified\`: Whether the session token itself is verified (no pending token verification)
93+
- \`details.sessionVerificationMeetsMinimumAAL\`: Whether the session's Authentication Assurance Level (AAL) meets or exceeds the account's maximum AAL
94+
- \`details.verified\`: Deprecated! Use accountEmailVerified and sessionVerified instead.
8695
`,
8796
],
8897
};
@@ -95,6 +104,16 @@ const SESSION_DUPLICATE_POST = {
95104
🔒 Authenticated with session token
96105
97106
Create a new \`sessionToken\` that duplicates the current session. It will have the same verification status as the current session, but will have a distinct verification code.
107+
108+
**Response object:**
109+
- \`uid\`: Account id
110+
- \`sessionToken\`: Session Token
111+
- \`authAt\`: Authentication timestamp
112+
- \`emailVerified\`: Whether the account's primary email is verified
113+
- \`sessionVerified\`: Whether the session token itself is verified (no pending token verification)
114+
- \`verificationMethod\`: Present if verification is incomplete, e.g. \`email\`, \`email-2fa\`, \`email-otp\`, \`totp-2fa\`
115+
- \`verificationReason\`: Present if verification is incomplete, e.g. \`login\`, \`signup\`
116+
- \`verified\`: Deprecated! Use emailVerified and sessionVerified instead.
98117
`,
99118
],
100119
};
@@ -129,7 +148,7 @@ const SESSION_VERIFY_PUSH_POST = {
129148
notes: [
130149
dedent`
131150
🔒 Authenticated with session token
132-
151+
133152
Endpoint that accepts a code and tokenVerificationId to verify a session.
134153
`,
135154
],

packages/fxa-auth-server/lib/routes/session.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ module.exports = function (
151151
sessionVerified: isA.boolean().required(),
152152
authAt: isA.number().integer(),
153153
metricsEnabled: isA.boolean().required(),
154+
verified: isA.boolean().required(), // Deprecated!
154155
}),
155156
},
156157
},
@@ -281,6 +282,11 @@ module.exports = function (
281282
)
282283
);
283284

285+
// Needed to prevent breaking API changes!
286+
// Legacy implemenation would set verified true when
287+
// session and email are flagged as verified
288+
response.verified = response.emailVerified && response.sessionVerified;
289+
284290
return response;
285291
},
286292
},
@@ -301,6 +307,7 @@ module.exports = function (
301307
sessionVerificationMethod: isA.string().allow(null),
302308
sessionVerified: isA.boolean(),
303309
sessionVerificationMeetsMinimumAAL: isA.boolean(),
310+
verified: isA.boolean(), // Deprecated!
304311
}),
305312
}),
306313
},
@@ -335,6 +342,9 @@ module.exports = function (
335342
// Account Assurance Level
336343
const sessionVerificationMeetsMinimumAAL = sessionAal >= accountAal;
337344

345+
// Legacy verified flag. Keep for backwards compatibility.
346+
const verified = accountEmailVerified && sessionVerified;
347+
338348
return {
339349
state: sessionToken.state,
340350
uid: sessionToken.uid,
@@ -343,6 +353,7 @@ module.exports = function (
343353
sessionVerificationMethod,
344354
sessionVerified,
345355
sessionVerificationMeetsMinimumAAL,
356+
verified,
346357
},
347358
};
348359
},
@@ -361,6 +372,18 @@ module.exports = function (
361372
reason: isA.string().max(16).optional(),
362373
}),
363374
},
375+
response: {
376+
schema: isA.object({
377+
uid: isA.string().regex(HEX_STRING).required(),
378+
sessionToken: isA.string().regex(HEX_STRING).required(),
379+
authAt: isA.number().integer(),
380+
emailVerified: isA.boolean(),
381+
sessionVerified: isA.boolean(),
382+
verificationMethod: isA.string().allow(null),
383+
verificationReason: isA.string().allow(null),
384+
verified: isA.boolean(), // Deprecated
385+
}),
386+
},
364387
},
365388
handler: async function (request) {
366389
log.begin('Session.duplicate', request);
@@ -410,6 +433,10 @@ module.exports = function (
410433
response.sessionVerified = true;
411434
}
412435

436+
// Prevents breaking API changes!
437+
response.verified =
438+
newSessionToken.emailVerified && newSessionToken.tokenVerified;
439+
413440
return response;
414441
},
415442
},

packages/fxa-auth-server/test/local/routes/session.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ describe('/session/status', () => {
210210
sessionVerificationMeetsMinimumAAL: false,
211211
sessionVerificationMethod: 'totp-2fa',
212212
sessionVerified: false,
213+
verified: false,
213214
},
214215
});
215216
});
@@ -246,6 +247,7 @@ describe('/session/status', () => {
246247
accountEmailVerified: false,
247248
sessionVerificationMethod: 'email',
248249
sessionVerified: false,
250+
verified: false,
249251
sessionVerificationMeetsMinimumAAL: true,
250252
},
251253
});
@@ -281,6 +283,7 @@ describe('/session/status', () => {
281283
accountEmailVerified: false,
282284
sessionVerificationMethod: 'email',
283285
sessionVerified: false,
286+
verified: false,
284287
sessionVerificationMeetsMinimumAAL: true,
285288
},
286289
});
@@ -316,6 +319,7 @@ describe('/session/status', () => {
316319
accountEmailVerified: true,
317320
sessionVerificationMethod: 'email',
318321
sessionVerified: false,
322+
verified: false,
319323
sessionVerificationMeetsMinimumAAL: false,
320324
},
321325
});
@@ -351,6 +355,7 @@ describe('/session/status', () => {
351355
accountEmailVerified: true,
352356
sessionVerificationMethod: 'totp-2fa',
353357
sessionVerified: true,
358+
verified: true,
354359
sessionVerificationMeetsMinimumAAL: false,
355360
},
356361
});
@@ -385,6 +390,7 @@ describe('/session/status', () => {
385390
accountEmailVerified: true,
386391
sessionVerificationMethod: 'email',
387392
sessionVerified: true,
393+
verified: true,
388394
sessionVerificationMeetsMinimumAAL: true,
389395
},
390396
});
@@ -420,6 +426,7 @@ describe('/session/status', () => {
420426
accountEmailVerified: true,
421427
sessionVerificationMethod: 'totp-2fa',
422428
sessionVerified: true,
429+
verified: true,
423430
sessionVerificationMeetsMinimumAAL: true,
424431
},
425432
});
@@ -519,6 +526,7 @@ describe('/session/reauth', () => {
519526
);
520527
signinUtils.getSessionVerificationStatus = sinon.spy(() => ({
521528
sessionVerified: true,
529+
verified: true,
522530
}));
523531
const testNow = Math.floor(Date.now() / 1000);
524532
return runTest(route, request).then((res) => {
@@ -720,7 +728,7 @@ describe('/session/reauth', () => {
720728

721729
assert.equal(
722730
Object.keys(res).length,
723-
6,
731+
7,
724732
'response object had correct number of keys'
725733
);
726734
assert.equal(res.uid, TEST_UID, 'response object contained correct uid');
@@ -743,6 +751,11 @@ describe('/session/reauth', () => {
743751
true,
744752
'response object indicated correct session verification status'
745753
);
754+
assert.equal(
755+
res.verified,
756+
true,
757+
'response object indicated correct legacy session verified status'
758+
);
746759
});
747760
});
748761

@@ -1165,7 +1178,7 @@ describe('/session/duplicate', () => {
11651178
return runTest(route, request).then((res) => {
11661179
assert.equal(
11671180
Object.keys(res).length,
1168-
5,
1181+
6,
11691182
'response has correct number of keys'
11701183
);
11711184
assert.equal(
@@ -1189,6 +1202,11 @@ describe('/session/duplicate', () => {
11891202
true,
11901203
'response includes correctly-copied session verification flag'
11911204
);
1205+
assert.equal(
1206+
res.verified,
1207+
true,
1208+
'response includes correctly-copied leagacy session verified flag'
1209+
);
11921210

11931211
assert.equal(
11941212
db.createSessionToken.callCount,
@@ -1283,7 +1301,7 @@ describe('/session/duplicate', () => {
12831301
return runTest(route, request).then((res) => {
12841302
assert.equal(
12851303
Object.keys(res).length,
1286-
7,
1304+
8,
12871305
'response has correct number of keys'
12881306
);
12891307
assert.equal(
@@ -1307,6 +1325,11 @@ describe('/session/duplicate', () => {
13071325
false,
13081326
'response includes correctly-copied session verification flag'
13091327
);
1328+
assert.equal(
1329+
res.verified,
1330+
false,
1331+
'response includes correctly-copied legacy session verified flag'
1332+
);
13101333
assert.equal(
13111334
res.verificationMethod,
13121335
'email',
@@ -1414,7 +1437,7 @@ describe('/session/duplicate', () => {
14141437
return runTest(route, request).then((res) => {
14151438
assert.equal(
14161439
Object.keys(res).length,
1417-
7,
1440+
8,
14181441
'response has correct number of keys'
14191442
);
14201443
assert.equal(
@@ -1438,6 +1461,11 @@ describe('/session/duplicate', () => {
14381461
true,
14391462
'response includes correctly-copied session verification flag'
14401463
);
1464+
assert.equal(
1465+
res.verified,
1466+
false,
1467+
'response includes correctly-copied legacy session verified flag'
1468+
);
14411469
assert.equal(
14421470
res.verificationMethod,
14431471
'email',

packages/fxa-auth-server/test/remote/session_tests.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ const config = require('../../config').default.getProperties();
543543
sessionVerificationMeetsMinimumAAL: true,
544544
sessionVerificationMethod: null,
545545
sessionVerified: false,
546+
verified: false,
546547
},
547548
});
548549
});

0 commit comments

Comments
 (0)