Skip to content

iOS SDK wipes permanent sessions & caches sessions on launch while initialSession returns nil, causing ghost-session #753

@vojtabohm

Description

@vojtabohm

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

On app launch the iOS SDK briefly surfaces the cached session via
supabase.auth.currentSession, but immediately afterward it nukes that session and emits
initialSession with
session == nil. Any request made afterward fails with AuthError.sessionMissing (a “ghost session” state). Assuming you let the user optimistically in based on the synchronous supabase.auth.currentSession check.

There are no custom session expiration settings in the project; defaults are used. There is no reason why it should be nuked.

To Reproduce

  1. Sign in with any user in an iOS app using supabase-swift.

  2. Kill the app or wait for the system to kill it.

  3. Relaunch after a few days.

  4. Immediately read supabase.auth.currentSession → it is non-nil.

  5. Attach for await authStateChanges.

  6. The first callback you receive is:

    event = initialSession
    session = nil
    
  7. Subsequent supabase.auth.currentSession is now nil, and any REST call
    returns sessionMissing.

Console output:

// ON APP LAUNCH:
let isSignedIn = supabase.auth.currentSession != nil
print("Is signed in? \(supabase.auth.currentSession?.hashValue)")
print("Is signed in? \(supabase.auth.currentUser?.email)")

-> Is signed in? Optional(2166808766723586244)
-> Is signed in? Optional("[email protected]")

// AFTER ATTACHING OBSERVERS:
private func setupAuthListener() {
        Task {
            for await (event, session) in supabase.auth.authStateChanges {
                print("Auth change:", event, session?.hashValue, session?.expiresAt, session?.isExpired)
                switch event {
                case .initialSession:
                    print("INITIAL SESSION", session?.hashValue)
                    ....

                    
-> Auth change: initialSession nil nil nil

// AFTER CALLING HTTP REQUESTS THAT WANT TO REFRESH A TOKEN FROM SUPABASE USING
// try await supabase.auth.session
-> sessionMissing

Expected behavior

  1. SDK shouldn't nuke the sessions in the first place.

  2. Make the nuking explicit
    a) The cached session is still valid → SDK should emit initialSession(session:) with that same session, or
    b) The cached session is invalid → SDK should emit initialSession with the cached session object (isExpired == true) followed by signedOut, or attempt a silent tokenRefreshed before wiping it.

Silently deleting the session and returning nil makes it impossible to distinguish “first launch” from “previously signed-in user whose refresh token was lost”, and leads to ghost-session states.

Screenshots

N/A (console logs included above).

System information

  • OS: iOS 17.5 / macOS 14.5 (reproduced on both simulator and device)
  • Supabase version: 2.26.1
  • Xcode: 15.4

Additional context

A doc note (“don’t trust currentSession until after the firstinitialSession event”) would help, but ideally the SDK should not wipe the cached session without emitting a reasoned event.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions