Commit b3b8320
authored
fix(auth): Consistent device metadata keychain key across auth flows (#4196)
* fix(auth): Use original user input as device metadata keychain key
The device metadata keychain key was derived from SignedInData.username,
which is parsed from the JWT access token. Cognito returns different
username claims depending on the auth flow: USER_PASSWORD_AUTH returns
the internal sub-style UUID while USER_SRP_AUTH returns the user alias
(email, phone, etc). This caused device metadata stored during one flow
to be unretrievable during another, resulting in duplicate device IDs
on every login when switching between auth flows.
Thread the original user-typed username (inputUsername) through
SignedInData, RespondToAuthChallenge, and the parseResponse/
sendRespondToAuth helper chain so that ConfirmDevice always stores
device metadata under the same key that InitializeSignInFlow will use
for retrieval on subsequent logins.
The inputUsername field is optional on both structs to maintain
backwards compatibility with existing keychain-persisted data.
* test(auth): Add unit and integration tests for device key persistence fix
Unit tests (12 tests):
- SignedInData Codable backwards compatibility (decode without inputUsername)
- SignedInData and AmplifyCredentials round-trip with inputUsername
- RespondToAuthChallenge inputUsername encode/decode
- parseResponse threading of inputUsername to confirmDevice, finalizeSignIn, challenge events
- VerifyPasswordSRP forwarding inputUsername through confirmDevice
- VerifySignInChallenge forwarding challenge.inputUsername through confirmDevice
Integration tests (2 tests):
- Device ID persists across sign-out/sign-in cycles (no duplicates)
- Device count remains stable across multiple sign-in cycles
* test(auth): Add cross-flow integration tests for device key persistence
Add integration tests that explicitly switch between USER_PASSWORD_AUTH
and USER_SRP_AUTH flows to verify device key persists across flow changes:
- testDeviceKeyPersistsFromUserPasswordToUserSRP
- testDeviceKeyPersistsFromUserSRPToUserPassword
- testDeviceKeyStableAcrossAlternatingAuthFlows (4 cycles alternating)
- testDeviceKeyPersistsAcrossSignOutSignIn (same flow baseline)
Each test uses AWSAuthSignInOptions(authFlowType:) to explicitly select
the auth flow per sign-in attempt.
* chore(auth): Add integration test to Xcode project target membership
Add DeviceKeyPersistenceIntegrationTests.swift to all 3 AuthIntegrationTests
build phases in the AuthHostApp Xcode project so the tests are discoverable
by xcodebuild test-without-building.
* chore: Fix trailing whitespace in RESTRequestUtilsTests
Pre-existing swiftformat violation on blank lines.
* fix(auth): Address review feedback on inputUsername
- Add inputUsername to SignedInData.debugDictionary
- Change SignedInData.inputUsername from var to let (has explicit init)
- Keep RespondToAuthChallenge.inputUsername as var since it relies on
synthesized memberwise init with implicit nil default
* fix(auth): Normalize device metadata keychain key to lowercase
Cognito normalizes usernames to lowercase in JWT claims, but the
user-typed input preserves original casing. This caused a keychain
key mismatch when storing device metadata with inputUsername (mixed
case) and retrieving with the JWT username (lowercase).
Lowercase the username in generateDeviceMetadataKey — the single
funnel point for all device metadata store/retrieve/remove operations.1 parent d5ca7e8 commit b3b8320
13 files changed
Lines changed: 741 additions & 13 deletions
File tree
- AmplifyPlugins/Auth
- Sources/AWSCognitoAuthPlugin
- Actions/SignIn
- DeviceSRPAuth
- SRPAuth
- WebAuthn
- CredentialStorage
- StateMachine/CodeGen/Data
- Support/Helpers
- Tests
- AWSCognitoAuthPluginUnitTests/ActionTests/DeviceKeyPersistence
- AuthHostApp
- AuthHostApp.xcodeproj
- AuthIntegrationTests/DeviceTests
Lines changed: 4 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
61 | | - | |
| 61 | + | |
| 62 | + | |
62 | 63 | | |
| 64 | + | |
63 | 65 | | |
64 | | - | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| 82 | + | |
82 | 83 | | |
83 | 84 | | |
84 | 85 | | |
| |||
Lines changed: 3 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
| 148 | + | |
148 | 149 | | |
149 | 150 | | |
150 | 151 | | |
151 | 152 | | |
152 | 153 | | |
153 | 154 | | |
154 | | - | |
| 155 | + | |
| 156 | + | |
155 | 157 | | |
156 | 158 | | |
157 | 159 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
| 83 | + | |
83 | 84 | | |
84 | 85 | | |
85 | 86 | | |
| |||
Lines changed: 5 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
| 100 | + | |
100 | 101 | | |
101 | 102 | | |
102 | 103 | | |
| |||
202 | 203 | | |
203 | 204 | | |
204 | 205 | | |
205 | | - | |
| 206 | + | |
| 207 | + | |
206 | 208 | | |
207 | 209 | | |
208 | 210 | | |
| |||
220 | 222 | | |
221 | 223 | | |
222 | 224 | | |
223 | | - | |
| 225 | + | |
| 226 | + | |
224 | 227 | | |
225 | 228 | | |
226 | 229 | | |
| |||
Lines changed: 2 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | | - | |
| 60 | + | |
| 61 | + | |
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
151 | | - | |
| 151 | + | |
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
| |||
Lines changed: 2 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
Lines changed: 6 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
23 | | - | |
| 24 | + | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
30 | 32 | | |
31 | 33 | | |
32 | 34 | | |
| 35 | + | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
| |||
46 | 49 | | |
47 | 50 | | |
48 | 51 | | |
49 | | - | |
| 52 | + | |
| 53 | + | |
50 | 54 | | |
51 | 55 | | |
52 | 56 | | |
| |||
Lines changed: 13 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
| 76 | + | |
76 | 77 | | |
77 | 78 | | |
78 | 79 | | |
79 | 80 | | |
80 | 81 | | |
81 | | - | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
82 | 88 | | |
83 | 89 | | |
84 | 90 | | |
| |||
87 | 93 | | |
88 | 94 | | |
89 | 95 | | |
90 | | - | |
| 96 | + | |
| 97 | + | |
91 | 98 | | |
92 | 99 | | |
93 | 100 | | |
| |||
104 | 111 | | |
105 | 112 | | |
106 | 113 | | |
107 | | - | |
| 114 | + | |
| 115 | + | |
108 | 116 | | |
109 | 117 | | |
110 | 118 | | |
| |||
121 | 129 | | |
122 | 130 | | |
123 | 131 | | |
124 | | - | |
| 132 | + | |
| 133 | + | |
125 | 134 | | |
126 | 135 | | |
127 | 136 | | |
| |||
0 commit comments