Skip to content

fix: stop push notifications after session expires without explicit logout - #312

Open
deaflynx wants to merge 6 commits into
thingsboard:develop/1.9.0from
deaflynx:fix/push-notifications-after-logout-304
Open

fix: stop push notifications after session expires without explicit logout#312
deaflynx wants to merge 6 commits into
thingsboard:develop/1.9.0from
deaflynx:fix/push-notifications-after-logout-304

Conversation

@deaflynx

Copy link
Copy Markdown
Contributor

Fixes #304

Merge of the CE fix (thingsboard/flutter_thingsboard_app#248) into PE.

Problem

When the session ends without an explicit logout (refresh token expires while the app is unused), the FCM token stays registered on the platform and the device keeps receiving alarm push notifications after the automatic logout.

Solution

  • Persist a push_notifications_registered flag (TbStorage) whenever the FCM token is registered with the platform — on a fresh saveMobileSession and when init() finds an existing valid session (covers installs upgrading to this version).
  • New NotificationService.handleSessionExpired(): if the flag is set, runs the full push cleanup and clears the flag. Deleting the local FCM token is what actually stops delivery — the JWT is already invalid at this point, so the server-side removeMobileSession call usually cannot succeed; subsequent pushes to the deleted token bounce with UNREGISTERED and the platform purges the mobile session on the next delivery attempt.
  • Login.handleUserLoaded() triggers the cleanup whenever it detects an unauthenticated client with Firebase configured. Because the trigger is the persisted flag (not the in-memory login state), it works on cold start — the main reported scenario (app killed, token expired days ago) — as well as when the expiry happens while the app is running. It is a no-op on fresh installs, after manual logout, and on subsequent logged-out launches.
  • NotificationService.logout() now awaits removeMobileSession inside a try/catch: previously the call was fire-and-forget and produced an unhandled async error exactly in the expired-token case.

Limitations

Pushes delivered between the token expiry and the next app launch cannot be stopped from the client — closing that gap requires a platform-side change (tying mobile session lifetime to the auth session), which is being discussed separately.

Testing

  • Unit tests for the handleSessionExpired flag logic (test/utils/services/notification_service_test.dart), passing on the PE tree.
  • flutter analyze — no new findings on touched files.

deaflynx and others added 4 commits July 2, 2026 18:26
@deaflynx deaflynx added the bug Something isn't working label Aug 20, 2026
@deaflynx deaflynx added this to the 1.9.0 milestone Aug 20, 2026
…board#304)

- await Firebase init in main() so the apps.isNotEmpty guards are
  deterministic, and move the Firebase-configured guard into
  NotificationService instead of copying it at every call site
- persist the push-registration flag via DatabaseKeys and
  ILocalDatabaseService, checked with containsKey instead of a string
  sentinel
- rename handleSessionExpired to cleanUpStalePushRegistration and split
  the local teardown out of logout() into _cleanupPushRegistration()
- handle failures of the remaining fire-and-forget removeMobileSession
  calls (token refresh listener, _resetToken) and clear the cached FCM
  token after deletion
- fix TbContext.logout() calling NotificationService.init() instead of
  logout()
- drive the real cleanup path in tests via injectable Firebase
  collaborators and pin the persisted key contract
…logout-304' into fix/push-notifications-after-logout-304

# Conflicts:
#	lib/main.dart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant