Skip to content

fix(ios): use deleteToken in refreshToken to avoid race#189

Open
eljass wants to merge 1 commit into
capacitor-community:masterfrom
eljass:upstream/fix-ios-refresh-token
Open

fix(ios): use deleteToken in refreshToken to avoid race#189
eljass wants to merge 1 commit into
capacitor-community:masterfrom
eljass:upstream/fix-ios-refresh-token

Conversation

@eljass

@eljass eljass commented May 7, 2026

Copy link
Copy Markdown

What

Fixes two issues in the iOS refreshToken implementation:

  1. Race conditionMessaging.messaging().token { ... } ran in parallel with deleteData { ... } rather than after. The new token fetch could resolve before the delete completed and return the same token.

  2. Overly broad APIdeleteData() deletes all Messaging data; deleteToken() is the Firebase-recommended call for FCM token rotation.

Also removes a duplicate CAP_PLUGIN_METHOD(refreshToken, CAPPluginReturnPromise) registration in Plugin.m.

Why

Reported in our app: rotating the FCM token sometimes returned the previous value, breaking server-side token replacement. The fix follows the Firebase iOS docs and matches the Android implementation in this plugin (which already nests deleteTokengetToken correctly).

Test plan

  • Built against Capacitor 8 and Firebase iOS SDK 11.x in our app
  • Confirmed refreshToken() returns a different token from getToken()
  • Verified no regression in Analytics/Crashlytics installation correlation (unlike Installations.delete() which would invalidate it)

Notes

No API change. No new dependencies. Android unchanged.

The community master had two bugs in refreshToken on iOS:

1. Race condition: token() ran in parallel with deleteData(), not
   after it completed. The new token could be fetched before the old
   one was deleted, potentially returning the same token.

2. Used deleteData() which deletes all Messaging data, broader than
   necessary for token rotation.

This fix:
- Uses Messaging.messaging().deleteToken() — the Firebase-recommended
  API that only invalidates the current FCM token
- Nests the token fetch inside the delete completion handler, ensuring
  proper sequencing (delete completes → then fetch new token)
- Preserves Analytics/Crashlytics installation correlation (unlike the
  fork's Installations.delete approach)
- Removes duplicate refreshToken registration in Plugin.m

The Android implementation was already correct (properly nested
deleteToken → getToken) and is unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant