Skip to content

Commit 2706cb0

Browse files
JcMinarroCopilot
andauthored
Expire token only when it is needed (#5816)
* Expire token only when it is needed * Update stream-chat-android-client/src/test/java/io/getstream/chat/android/client/socket/SocketFactoryTest.kt Co-authored-by: Copilot <[email protected]> * Update CHANGELOG.md --------- Co-authored-by: Copilot <[email protected]>
1 parent 46f8669 commit 2706cb0

File tree

5 files changed

+55
-12
lines changed

5 files changed

+55
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
### ⬆️ Improved
1717
- Add `ChannelInfo` fallback to `Message` when parsing from API and/or Events. [#5813](https://github.com/GetStream/stream-chat-android/pull/5813)
18+
- Refresh token only during WS reconnection when the reconnection is triggered by a token issue. [#5816](https://github.com/GetStream/stream-chat-android/pull/5816)
1819

1920
### ✅ Added
2021

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/socket/ChatSocket.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ internal open class ChatSocket(
138138
is State.Disconnected -> {
139139
when (state) {
140140
is State.Disconnected.DisconnectedByRequest -> {
141+
tokenManager.expireToken()
141142
streamWebSocket?.close()
142143
healthMonitor.stop()
143144
userScope.launch { disposeObservers() }
@@ -152,6 +153,7 @@ internal open class ChatSocket(
152153
disposeNetworkStateObserver()
153154
}
154155
is State.Disconnected.DisconnectedPermanently -> {
156+
tokenManager.expireToken()
155157
streamWebSocket?.close()
156158
healthMonitor.stop()
157159
userScope.launch { disposeObservers() }
@@ -160,6 +162,7 @@ internal open class ChatSocket(
160162
healthMonitor.onDisconnected()
161163
}
162164
is State.Disconnected.WebSocketEventLost -> {
165+
tokenManager.expireToken()
163166
streamWebSocket?.close()
164167
connectionConf?.let { chatSocketStateService.onReconnect(it, false) }
165168
}

stream-chat-android-client/src/main/java/io/getstream/chat/android/client/socket/SocketFactory.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@ internal class SocketFactory(
6565
when (connectionConf) {
6666
is ConnectionConf.AnonymousConnectionConf -> "$baseWsUrl&stream-auth-type=anonymous"
6767
is ConnectionConf.UserConnectionConf -> {
68+
tokenManager.ensureTokenLoaded()
6869
val token = tokenManager.getToken()
69-
.takeUnless { connectionConf.isReconnection }
70-
?: tokenManager.loadSync()
7170
"$baseWsUrl&authorization=$token&stream-auth-type=jwt"
7271
}
7372
}

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/socket/SocketFactoryTest.kt

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import io.getstream.chat.android.client.parser2.ParserFactory
2121
import io.getstream.chat.android.client.token.FakeTokenManager
2222
import io.getstream.chat.android.client.utils.HeadersUtil
2323
import io.getstream.chat.android.models.User
24+
import io.getstream.chat.android.randomBoolean
2425
import io.getstream.chat.android.randomString
2526
import io.getstream.chat.android.randomUser
2627
import okhttp3.OkHttpClient
@@ -45,17 +46,18 @@ internal class SocketFactoryTest {
4546
whenever(this.newWebSocket(any(), any())) doReturn mock()
4647
}
4748

48-
private val socketFactory = SocketFactory(
49-
chatParser,
50-
FakeTokenManager(token, loadSyncToken),
51-
headersUtil,
52-
httpClient,
53-
)
54-
5549
/** [arguments] */
5650
@ParameterizedTest
5751
@MethodSource("arguments")
58-
internal fun testCreateSocket(connectionConf: SocketFactory.ConnectionConf, expectedUrl: String) {
52+
internal fun testCreateSocket(
53+
expireToken: Boolean,
54+
connectionConf: SocketFactory.ConnectionConf,
55+
expectedUrl: String,
56+
) {
57+
val socketFactory = Fixture(httpClient)
58+
.withExpire(expireToken)
59+
.get()
60+
5961
socketFactory.createSocket(connectionConf)
6062

6163
verify(httpClient, only()).newWebSocket(
@@ -66,6 +68,21 @@ internal class SocketFactoryTest {
6668
)
6769
}
6870

71+
private class Fixture(val httpClient: OkHttpClient) {
72+
private val tokenManager = FakeTokenManager(token, loadSyncToken)
73+
74+
fun withExpire(expire: Boolean): Fixture = apply {
75+
tokenManager.takeIf { expire }?.expireToken()
76+
}
77+
78+
fun get() = SocketFactory(
79+
chatParser,
80+
tokenManager,
81+
headersUtil,
82+
httpClient,
83+
)
84+
}
85+
6986
companion object {
7087
private val chatParser: ChatParser = ParserFactory.createMoshiChatParser()
7188
private val endpoint = "https://${randomString().lowercase(Locale.getDefault())}/"
@@ -81,24 +98,42 @@ internal class SocketFactoryTest {
8198
fun arguments() = listOf(
8299
randomUser(image = randomString(), name = randomString(), language = randomString()).let {
83100
Arguments.of(
101+
false,
84102
SocketFactory.ConnectionConf.UserConnectionConf(endpoint, apiKey, it),
85103
"${endpoint}connect?json=${buildFullUserJson(it, it.id)}&api_key=$apiKey&X-Stream-Client=${headersUtil.buildSdkTrackingHeaders()}&authorization=$token&stream-auth-type=jwt",
86104
)
87105
},
88106
randomUser().let {
89107
Arguments.of(
108+
false,
109+
SocketFactory.ConnectionConf.UserConnectionConf(endpoint, apiKey, it).asReconnectionConf(),
110+
"${endpoint}connect?json=${buildMinimumUserJson(it.id)}&api_key=$apiKey&X-Stream-Client=${headersUtil.buildSdkTrackingHeaders()}&authorization=$token&stream-auth-type=jwt",
111+
)
112+
},
113+
randomUser(image = randomString(), name = randomString(), language = randomString()).let {
114+
Arguments.of(
115+
true,
116+
SocketFactory.ConnectionConf.UserConnectionConf(endpoint, apiKey, it),
117+
"${endpoint}connect?json=${buildFullUserJson(it, it.id)}&api_key=$apiKey&X-Stream-Client=${headersUtil.buildSdkTrackingHeaders()}&authorization=$loadSyncToken&stream-auth-type=jwt",
118+
)
119+
},
120+
randomUser().let {
121+
Arguments.of(
122+
true,
90123
SocketFactory.ConnectionConf.UserConnectionConf(endpoint, apiKey, it).asReconnectionConf(),
91124
"${endpoint}connect?json=${buildMinimumUserJson(it.id)}&api_key=$apiKey&X-Stream-Client=${headersUtil.buildSdkTrackingHeaders()}&authorization=$loadSyncToken&stream-auth-type=jwt",
92125
)
93126
},
94127
User("anon").let {
95128
Arguments.of(
129+
randomBoolean(),
96130
SocketFactory.ConnectionConf.AnonymousConnectionConf(endpoint, apiKey, it).asReconnectionConf(),
97131
"${endpoint}connect?json=${buildMinimumUserJson(it.id)}&api_key=$apiKey&X-Stream-Client=${headersUtil.buildSdkTrackingHeaders()}&stream-auth-type=anonymous",
98132
)
99133
},
100134
User("!anon").let {
101135
Arguments.of(
136+
randomBoolean(),
102137
SocketFactory.ConnectionConf.AnonymousConnectionConf(endpoint, apiKey, it).asReconnectionConf(),
103138
"${endpoint}connect?json=${buildMinimumUserJson("anon")}&api_key=$apiKey&X-Stream-Client=${headersUtil.buildSdkTrackingHeaders()}&stream-auth-type=anonymous",
104139
)

stream-chat-android-client/src/test/java/io/getstream/chat/android/client/token/FakeTokenManager.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,19 @@ internal class FakeTokenManager(
2121
private val loadSyncToken: String = token,
2222
) : TokenManager {
2323

24+
private var expired = false
25+
2426
override fun loadSync(): String = loadSyncToken.also {
2527
token = loadSyncToken
2628
}
2729

2830
override fun getToken(): String = token
2931

3032
override fun ensureTokenLoaded() {
31-
// empty
33+
if (expired) {
34+
loadSync()
35+
}
36+
expired = false
3237
}
3338

3439
override fun setTokenProvider(provider: CacheableTokenProvider) {
@@ -44,6 +49,6 @@ internal class FakeTokenManager(
4449
}
4550

4651
override fun expireToken() {
47-
// empty
52+
expired = true
4853
}
4954
}

0 commit comments

Comments
 (0)