@@ -21,6 +21,8 @@ import com.amplifyframework.statemachine.codegen.data.asIdToken
2121import com.amplifyframework.statemachine.codegen.data.asRefreshToken
2222import io.kotest.matchers.shouldBe
2323import java.time.Instant
24+ import kotlinx.serialization.encodeToString
25+ import kotlinx.serialization.json.Json
2426import org.junit.Test
2527
2628class TokensTest {
@@ -89,4 +91,115 @@ class TokensTest {
8991 " CognitoUserPoolTokens(idToken=eyJh***, accessToken=eyJh***, " +
9092 " refreshToken=eyJh***, expiration=null)"
9193 }
94+
95+ @Test
96+ fun `non nested tokens are parsed correctly` () {
97+ val flatFormatJson = """
98+ {
99+ "idToken": "$tokenString ",
100+ "accessToken": "$tokenString ",
101+ "refreshToken": "refresh_token_value",
102+ "expiration": 1756998578
103+ }
104+ """ .trimIndent()
105+
106+ val tokens = Json .decodeFromString<CognitoUserPoolTokens >(flatFormatJson)
107+
108+ tokens.idToken?.tokenValue shouldBe tokenString
109+ tokens.accessToken?.tokenValue shouldBe tokenString
110+ tokens.refreshToken?.tokenValue shouldBe " refresh_token_value"
111+ tokens.expiration shouldBe 1756998578L
112+
113+ // Verify JWT parsing still works
114+ tokens.accessToken?.userSub shouldBe " 1234567890"
115+ tokens.accessToken?.username shouldBe " jdoe"
116+ }
117+
118+ @Test
119+ fun `nested tokens are read correctly` () {
120+ val nestedFormatJson = """
121+ {
122+ "idToken": {"tokenValue": "$tokenString "},
123+ "accessToken": {"tokenValue": "$tokenString "},
124+ "refreshToken": {"tokenValue": "refresh_token_value"},
125+ "expiration": 1756998578
126+ }
127+ """ .trimIndent()
128+
129+ val tokens = Json .decodeFromString<CognitoUserPoolTokens >(nestedFormatJson)
130+
131+ tokens.idToken?.tokenValue shouldBe tokenString
132+ tokens.accessToken?.tokenValue shouldBe tokenString
133+ tokens.refreshToken?.tokenValue shouldBe " refresh_token_value"
134+ tokens.expiration shouldBe 1756998578L
135+
136+ // Verify JWT parsing still works after extracting from nested format
137+ tokens.accessToken?.userSub shouldBe " 1234567890"
138+ tokens.accessToken?.username shouldBe " jdoe"
139+ }
140+
141+ @Test
142+ fun `nested tokens are saved as non nested` () {
143+ // Start with nested format
144+ val nestedFormatJson = """
145+ {
146+ "idToken": {"tokenValue": "$tokenString "},
147+ "accessToken": {"tokenValue": "$tokenString "},
148+ "refreshToken": {"tokenValue": "refresh_token_value"},
149+ "expiration": 1756998578
150+ }
151+ """ .trimIndent()
152+
153+ // Deserialize nested format
154+ val tokens = Json .decodeFromString<CognitoUserPoolTokens >(nestedFormatJson)
155+
156+ // Serialize back to JSON
157+ val serializedJson = Json .encodeToString(tokens)
158+
159+ // Should now be in flat format
160+ val expectedFlatJson =
161+ """ {"idToken":"$tokenString ","accessToken":"$tokenString ","refreshToken":"refresh_token_value","expiration":1756998578}"""
162+ serializedJson shouldBe expectedFlatJson
163+
164+ // Verify we can deserialize the flat format again
165+ val tokensFromFlat = Json .decodeFromString<CognitoUserPoolTokens >(serializedJson)
166+ tokensFromFlat.idToken?.tokenValue shouldBe tokenString
167+ tokensFromFlat.accessToken?.tokenValue shouldBe tokenString
168+ tokensFromFlat.refreshToken?.tokenValue shouldBe " refresh_token_value"
169+ }
170+
171+ @Test
172+ fun `flat and nested formats produce identical results` () {
173+ val flatFormatJson = """
174+ {
175+ "idToken": "$tokenString ",
176+ "accessToken": "$tokenString ",
177+ "refreshToken": "refresh_token_value",
178+ "expiration": 1756998578
179+ }
180+ """ .trimIndent()
181+
182+ val nestedFormatJson = """
183+ {
184+ "idToken": {"tokenValue": "$tokenString "},
185+ "accessToken": {"tokenValue": "$tokenString "},
186+ "refreshToken": {"tokenValue": "refresh_token_value"},
187+ "expiration": 1756998578
188+ }
189+ """ .trimIndent()
190+
191+ val tokensFromFlat = Json .decodeFromString<CognitoUserPoolTokens >(flatFormatJson)
192+ val tokensFromNested = Json .decodeFromString<CognitoUserPoolTokens >(nestedFormatJson)
193+
194+ // Both should have identical token values
195+ tokensFromFlat.idToken?.tokenValue shouldBe tokensFromNested.idToken?.tokenValue
196+ tokensFromFlat.accessToken?.tokenValue shouldBe tokensFromNested.accessToken?.tokenValue
197+ tokensFromFlat.refreshToken?.tokenValue shouldBe tokensFromNested.refreshToken?.tokenValue
198+ tokensFromFlat.expiration shouldBe tokensFromNested.expiration
199+
200+ // Both should serialize to the same flat format
201+ val serializedFlat = Json .encodeToString(tokensFromFlat)
202+ val serializedNested = Json .encodeToString(tokensFromNested)
203+ serializedFlat shouldBe serializedNested
204+ }
92205}
0 commit comments