Skip to content

setAuth() not working when subscribing to broadcast database changes #713

Open
@baalexander

Description

@baalexander

I have been following the tutorial for Subscribing to Database Changes with the Swift client. The Swift client does not receive the database messages when triggered (like a record is updated), however, the JS client does receive the database messages.

I believe it's because supabase.realtimeV2.setAuth() does not send JWT credentials to channels because of this guard statement:

guard tokenToSend != mutableState.accessToken else {
    return
}

Spelunking session

  1. Initialize SupabaseClient (let supabase = SupabaseClient(...))
  2. On init, SupabaseClient calls listenForAuthEvents()
  3. listenForAuthEvents() calls handleTokenChanged(...)
  4. handleTokenChanges() calls await realtimeV2.setAuth(accessToken)

The problem seems to be that since await realtimeV2.setAuth(accessToken) is called in the initializing of SupabaseClient, it's triggered before we can subscribe to any channels. So if we have code like this:

let channel = supabase.channel("topic:id")
let broadcastStream = channel.broadcastStream(event: "UPDATE")
await channel.subscribe()
await supabase.realtimeV2.setAuth()
Task {
    for await message in broadcastStream {
        print("Message received", message)
    }

The setAuth() call does not send JWT auth to the channels, because the guard gets kicked in since the accessToken hasn't changed from initializing SupabaseClient:

realtimeV2.setAuth():

public func setAuth(_ token: String? = nil) async {
  var tokenToSend = token

  if tokenToSend == nil {
    tokenToSend = try? await options.accessToken?()
  }

  // 👇 guard kicks in, so the for channel in channels loop never get fired
  guard tokenToSend != mutableState.accessToken else {
    return
  }

  mutableState.withValue { [token] in
    $0.accessToken = token
  }

  for channel in channels.values {
    if channel.status == .subscribed {
      options.logger?.debug("Updating auth token for channel \(channel.topic)")
      await channel.push(
        ChannelEvent.accessToken,
        payload: ["access_token": token.map { .string($0) } ?? .null]
      )
    }
  }
}

Now it's very possible I'm just doing something wrong or completely missed a piece, but it seems like it's impossible to push accessTokens to channels since SupabaseClient sets the accessToken at initialization. Please let me know if I'm off base though and there's another reason!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions