Skip to content

auth.useUserAccessGroup(accessGroup) does not work to share authentication between Watch and iPhone #7854

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
RohitRajendran opened this issue Apr 6, 2021 · 9 comments

Comments

@RohitRajendran
Copy link
Contributor

RohitRajendran commented Apr 6, 2021

[REQUIRED] Step 1: Describe your environment

  • Xcode version: Version 12.4
  • Firebase SDK version: 7.9.1
  • Installation method: Swift Package Manager
  • Firebase Component: Auth

[REQUIRED] Step 2: Describe the problem

Steps to reproduce:

I'm trying to use Auth.auth().useUserAccessGroups across both iPhone and WatchOS apps to share authentication. The iPhone app initiates an anonymous sign in and should be sharing the user but the watch app returns nil.

  1. Setup an iPhone and WatchOS app and follow the following steps for cross app authentication https://firebase.google.com/docs/auth/ios/single-sign-on?authuser=0. I set up an app group and used that in both the iphone and watch app.
  2. In the iphone app, on init, utilize signInAnonymously after calling Auth.auth().useUserAccessGroup
  3. In the watch os app, on init, check the currentUser value after calling Auth.auth().useUserAccessGroup
  4. Run the iphone app and then the watch os app. The watch os app will return nil for user

Relevant Code:

In iPhone app:

init() {
        FirebaseApp.configure()

        do {
            Auth.auth().shareAuthStateAcrossDevices = true
            try Auth.auth().useUserAccessGroup("APP_GROUP_NAME")
        } catch let error as NSError {
            print("Error changing user access group: %@", error)
        }

        if Auth.auth().currentUser === nil {
            Auth.auth().signInAnonymously()
        }
        
        print(Auth.auth().currentUser?.uid, "user")
    }

In watch app:

init() {
        FirebaseApp.configure()

        do {
            Auth.auth().shareAuthStateAcrossDevices = true
            try Auth.auth().useUserAccessGroup("APP_GROUP_NAME")

            print(Auth.auth().currentUser?.uid, "user")
        } catch let error as NSError {
            print("Error changing user access group: %@", error)
        }
    }
@rizafran
Copy link
Contributor

Hi @RohitRajendran, would you mind sharing a minimal repro that I can run locally? It would help us a lot digging into the cause of your issue. Thanks.

@google-oss-bot
Copy link

Hey @RohitRajendran. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

@google-oss-bot
Copy link

Since there haven't been any recent updates here, I am going to close this issue.

@RohitRajendran if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.

@firebase firebase locked and limited conversation to collaborators May 29, 2021
@paulb777
Copy link
Member

Reopening based on conversation in #7840.

Note that watchOS is community supported so it may be awhile before anyone gets to this.

@paulb777 paulb777 reopened this Apr 27, 2022
@firebase firebase unlocked this conversation Apr 27, 2022
@dweekly
Copy link

dweekly commented Apr 28, 2022

Thanks for re-opening, Paul.

It would be good to have a "best practices for watchOS + iOS Firebase apps" doc that lives somewhere, even community-supported and with huge asterisks that it's not official yet.

I think there are a few options:

  1. Pass a Token
    Have the iPhone perform the auth flow and then retrieve a current token via Auth.auth().currentUser.getIDToken, then pass the token to the watch via a WCSession updateApplicationContext on session activation. Until the watchOS app receives the app context, it will have to display a "please log in on your iPhone" message to the user. This has the advantage of not actually requiring FirebaseAuth on the watchOS client at all - the watch app can just use the token in e.g. server API calls directly. The iOS app will be responsible for keeping its watch companion updated as the token renews and the watchOS app may need to enquire about a new token with the iOS parent app if it hears back that the token has expired.

The disadvantage of this approach is that it does not allow for a standalone watchOS app; the watch can only be used as a companion to the iOS app. In reality, very few apps are - or need to be - standalone; the watchOS App Store is a bit of a joke. So this should be fine for most developers.

  1. iCloud Keychain Sync
    Use a group/shared keychain between apps and enable iCloud Keychain synchronization, then direct Firebase Auth to use this shared keychain. In theory this enables all of a user's devices that are signed in with their iCloud account to also now be signed in with Firebase as the same user.

I haven't gotten this approach working yet but in theory it could/should work and it enables a full "acts like a peer" approach for watchOS as a client that enables an independent watchOS app experience. The phone and watch don't need to be communicating directly for this to work either; e.g. if the watch has a cellular connection it should be able to complete the iCloud sync.

  1. Proxy
    Have the iOS app pull all required data for the watchOS app and send it as app State. When the watchOS app opens, have it request information from (and send information to) the iPhone via WCSession messages.

This has the advantage of allowing for a much simpler and smaller watchOS client - the client never makes any "network" requests at all, just chatting with the host iOS app. No Firebase on-watch! The iOS app can use more sophisticated protocols like gRPC to talk to server backends to fulfill the request, none of which the watchOS app needs to be worried about. And the iOS app can just re-use existing code paths already needed to implement these things. The disadvantage is that all operations must be done in actively paired mode; the watchOS app will stop working altogether without an active WCSession, so the watch can never be far from the phone. That's probably an acceptable tradeoff for most apps.

  1. [DOESN'T WORK] App Group

It should be made clear to developers that setting up an app group for their watchOS extension and iOS app and then asking Firebase Auth to use that app group will NOT magically allow Firebase Auth to work correctly on-watch because app groups are used for on-device sharing and the watch and phone are separate devices. Clearly spelling this out will save developers heartache trying to figure out what's wrong.

@charlotteliang
Copy link
Contributor

@dweekly You are right, app group doesn't support data sharing between watch and iPhone. So unfortunately this issue is expected. We are looking at the possibilities of supporting this feature. In the meantime, @RohitRajendran and @dweekly It would be great to file a feature request and upvote the issue, which helps us prioritize.

@charlotteliang
Copy link
Contributor

@RohitRajendran @dweekly Can you share a bit about your use case? Do you use other Firebase products on watch that need authentication or you want to only show user data when authentication is confirmed on watch?

For the second case, you can use WatchConnectivity to notify you watch if user has authenticated on the iPhone.

@qusc
Copy link

qusc commented Jun 13, 2023

I'm trying to figure this out right now.
@dweekly I'm hesitant to go for the iCloud Keychain sync since I suppose it takes some time for it to sync / will be hard to control that.
I don't really just want to share the ID token retrieved via User.getIDTokenResult() either as it's short-lived and I want the watch app to be able to act independently from the iPhone. I could provide the long-lived refresh token via WatchConnectivity but there doesn't seem a way to use that to actually sign the user in (set the User object) using the Auth framework through public APIs.
I could maybe instead read the whole archived plist data from the keychain, send that to the watch, store it in the keychain there and only then initialize the Auth framework and have it read that data. Doesn't really sound elegant to me though.
Has anybody figured this out yet?
I'll probably go for providing the refresh token via WatchConnectivity, request the ID token from that (via REST) and use it to request Firebase APIs. That means I can't use any of the frameworks on the Watch though as they need the user object to be set for the Auth framework, right?

@importRyan
Copy link

This issue should be closed. The original usage of an app group (which is solely for exchanges among apps on one device) is the source of error. useUserAccessGroup(teamID.keyChainSharingGroup) does work for login and logout across Watch, iPhone, and Mac when the user has iCloud Keychain sync enabled.

@firebase firebase locked and limited conversation to collaborators Aug 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants