Iterable / react-native-sdk

MIT License
34 stars 30 forks source link

expiringAuthTokenRefreshPeriod and passing a token to Iterable.setEmail(email, token) don't work on iOS #529

Open buuuudzik opened 4 months ago

buuuudzik commented 4 months ago

Hi Iterable Folks!

Thanks for your efforts to make this SDK better.

Recently, I discovered these issues within this SDK: JWT token refreshing becomes inactive once I manually input the token into Iterable.setEmail(email, token). Even when I assign a specific value to config.expiringAuthTokenRefreshPeriod, this setting is disregarded.

I also noticed that the Iterable SDK might initiate registerDeviceToken before the JWT token is prepared. To address this, I attempted to manually provide a pre-fetched JWT token upon user change. Generally triggering registerDeviceToken or disableDevice without a valid JWT doesn't make any sense so it shouldn't be possible.

Additionally, I identified another issue where, occasionally, the first request made after the Iterable SDK retrieves a new JWT token still employs the outdated JWT token from the previous request.

And the last issue detected is that authHandler can be triggered after the app logged out (when the app is logged out the API used for generating the JWT token will return 401 error). It would be much easier to be sure that when we set Iterable.setEmail(null) authHandler won't be immediately triggered.

The below recording shows that there is no auto JWT token request from SDK which is set to 5 minutes: https://recordit.co/AJtf969F1v

Lib versions: "@iterable/react-native-sdk": "1.3.13", "react-native": "0.70.13", "iterableSdkVersion": "6.4.16",

OS: iOS 16.4 A recording was made in the simulator but it works exactly the same on a real device.

jena-chakour commented 2 months ago

Thanks for sharing this @buuuudzik-- quick clarity check, could you please confirm whether you're replacing the valid auth token before setting the email to null? If the authToken is expired, it's possible that the API won't work as expected.

buuuudzik commented 2 months ago

@jena-chakour Yes, I always kept the value of the previous email in a function to retrieve the token needed for the disableDevice query.

Currently, we are using the default JWT token refresh, which sometimes can use an expired token in the registerDeviceToken query and can ask for a refreshed token too late when the application is already logged out, and this query returns 401.

It would probably be good to add information in the documentation that, when manually passing the JWT token in the Iterable.setEmail(email, token) method, then the config.authHandler stops working. Initially, I wanted to supplement the default solution with manual calls to Iterable.setEmail(email, token) just before logging out and just after logging in. I didn't immediately notice that the default refresh is disabled despite setting config.authHandler, but also when I manually call Iterable.setEmail(email, token).

When manually using Iterable.setEmail(email, token), I noticed that the SDK sometimes still uses the previous token for the first registerDeviceToken query. Probably there is a race condition somewhere in the SDK when changing the token and sending registerDeviceToken and disableDevice queries.

Currently we've changed the implementation and we rely on SDK refetching mechanism which sometimes can fetch JWT token too late which in our app can produce 401 errors.

But when I've tried to patch it with a manual

jena-chakour commented 2 months ago

Thanks @buuuudzik, bringing this back to our team and will update further here as we have findings or followup questions to share-- let me know if any changes or questions come up on your side

jena-chakour commented 2 months ago

Hey @buuuudzik we will be making a change to remove JWT authentication for the disableDevice endpoint; will follow up here when that it released!