GetStream / stream-chat-swift

💬 iOS Chat SDK in Swift - Build your own app chat experience for iOS using the official Stream Chat API
https://getstream.io/chat/sdk/ios/
Other
861 stars 211 forks source link

Unexpected Authentication Error When Multiple App Access Keys are Present #2458

Closed bradleyrzeller closed 1 year ago

bradleyrzeller commented 1 year ago

What did you do?

We have mobile and web clients using a single stream app instance. Recently, a new App Access Key pair was added to this instance. Our backend, which vends user tokens (a jwt signed by the app secret) to our mobile apps, switched to this new key pair while our Android and iOS applications continued to use the old app key.

What did you expect to happen?

We expected that there would be no connection issues seen by any clients, using the original key.

What happened instead?

There were connection issues for roughly ~15% of our iOS users. There were also confirmed cased on Android but the volume is unknown. Internally, we had confirmed cases where some users could successfully connect and some could not.

The error received by the stream iOS client was:

Client is disconnected (Error WebSocket in .../stream-chat-swift/Sources/StreamChat/WebSocketClient/WebSocketClient.swift:208 -> ServerErrorPayload(code: 5, message: \"Connect failed with error: \"Token signature is invalid\"\", statusCode: 401)).)

GetStream Environment

GetStream Chat version: 4.20.0 GetStream Chat frameworks: StreamChat, StreamChatUI iOS version: 15.5-16.2 Swift version: 5 Xcode version: 13.x - 14.2 Device:: variety of iPhones and iPads

Additional context

A few critical questions:

testableapple commented 1 year ago

Hi @bradleyrzeller,

Just to double-check, it sounds like, for example, JWT is signed by the key B (a new one) but the client keeps sending the key A (the old one). If so, it won't authenticate this way. And if this is your case, you need to send the same apikey which JWT is signed with from your server.

Please let me know if this helps.

Best, Alex

bradleyrzeller commented 1 year ago

I hope to get a bit more clarity on this.

But yes, our mobile apps are configuring, the SDK with the original key, and the backend is using the new key pair to create tokens.

As mentioned above, the app key mismatch only broke a small percent of stream connections. The majority of iOS clients were able to connect successfully using the original app key and a stream user token signed with the new app secret. Why is this? If this is truly unsupported, I would expect 100% of connections to have failed during this time.

Also, if multiple app keys is truly not supported, what is the intended use of multiple app key pairs? Why would the dashboard even allow for this?

testableapple commented 1 year ago

Hi @bradleyrzeller,

if multiple app keys is truly not supported, what is the intended use of multiple app key pairs? Why would the dashboard even allow for this?

We do support multiple app key pairs. Although, you still have to use only one app key during the session. So it depends on the need, for example some clients may want to use different keys on different platforms.

The majority of iOS clients were able to connect successfully using the original app key and a stream user token signed with the new app secret. Why is this?

Technically this is not possible, authentication is done against the API key and secret.

Just to double-check, are you updating the key in the SDK when using different tokens?

Best, Alex

tbarbugli commented 1 year ago

@bradleyrzeller the use case here is to allow apps to rotate and revoke api key pairs without disruption, this would not be possible if an app only had 1 key pair available at all times (this approach would require a hard switch of keys).

When it comes to security we rather take the most conservative and simple approach, but I will bring this feedback to the backend and security team and see if it's feasible to make this easier to integrate.

In the meantime, you might want to consider returning both token and api key (the public part) to your mobile app, this way all API requests from mobile will always use key and token related to the same secret.

bradleyrzeller commented 1 year ago

Thanks for the help and clarification everyone. To close the loop - our initial understanding of the diagnosis was wrong, specifically the following statement:

Internally, we had confirmed cases where some users could successfully connect and some could not.

Our internal testing was wrong - we were not able to successfully connect. We cache tokens in the iOS keychain, which persists across uninstalls / re-installs. So a "fresh" install was actually using a prior cached stream token, signed by the prior app secret. So it worked, leading us to believe we were seeing mixed results.

glennposadas commented 1 year ago

Hey all. Sorry for bumping this, but we are currently experiencing this kind of issue. Do tokens have some kind of default expiration time? We are not adding an expiration time explicitly.