fix(realtime_client): suppress InvalidJWTToken from setAuth in joinPush 'ok' handler#1365
Open
theprantadutta wants to merge 2 commits into
Conversation
…sh 'ok' handler
The 'ok' callback registered by RealtimeChannel.subscribe() calls
socket.setAuth(socket.accessToken) without a try/catch. When the cached
access token has expired by the time the channel rejoins (e.g. after
the device wakes from a long background sleep), setAuth throws
FormatException('InvalidJWTToken: Invalid value for JWT claim "exp"
with value ...'). The async callback discards the returned Future, so
the error escapes into the zone error handler and is reported by
Sentry/Crashlytics as a fatal — even though the app recovers fine on
the next tokenRefreshed event.
The same exception is already filtered in
SupabaseClient._handleTokenChanged for the auth-state-change path; this
mirrors that filter on the rejoin path so the two re-auth code paths
behave consistently.
Closes supabase#1363
Collaborator
|
If you could fix the formatting issue, I think this looks great. Thanks! |
Matches the formatter settings used by CI (`dart format lib test -l 80 --set-exit-if-changed`).
Author
|
Thanks for the review @Vinzent03! Formatting fixed in |
Vinzent03
approved these changes
May 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1363.
RealtimeChannel.subscribe()registers anasync'ok'callback onjoinPushthat callssocket.setAuth(socket.accessToken)without atry/catch. When the cached access token has expired by the time the server replies'ok'(e.g. the device woke from a long background sleep and the channel rejoined before the auth refresh fired),setAuththrows:Because
Push.triggerinvokes the callback as avoid-returning function, the resultingFuture's error is discarded and surfaces in the zone error handler. Sentry / Crashlytics report it as a fatal even though the app keeps running and the nexttokenRefreshedevent recovers normally.SupabaseClient._handleTokenChangedalready filters this exact exception on the auth-state-change path:https://github.com/supabase/supabase-flutter/blob/main/packages/supabase/lib/src/supabase_client.dart#L379-L389
This PR mirrors that filter on the rejoin path so the two re-auth code paths behave consistently.
Change
packages/realtime_client/lib/src/realtime_channel.dart— wrap the rejoinsetAuthcall in the sameFormatException/InvalidJWTTokenfilter thatSupabaseClient._handleTokenChangeduses. OtherFormatExceptions still propagate.Tests
Added two unit tests in
packages/realtime_client/test/channel_test.dart:setAuththrowsFormatException('InvalidJWTToken: …')on rejoin, the'ok'handler still runs to completion and emitsRealtimeSubscribeStatus.subscribed. Without the fix this test fails (the callback aborts atsetAuthand the subscribed status is never emitted), confirming it genuinely validates the fix.InvalidJWTTokenFormatExceptions still abort the rejoin handler (subscribed is not emitted).Both tests use a
RealtimeClientsubclass that overridessetAuthto throw a controlled exception and overridesconnectto a no-op so transport-level async errors do not pollute the test runner zone.Test plan
dart test packages/realtime_client/test/channel_test.dart— both new tests pass; pre-existing tests unchangeddart analyzeclean forrealtime_client,supabase, andsupabase_flutter