firebase-ios-sdk icon indicating copy to clipboard operation
firebase-ios-sdk copied to clipboard

FR: Calling an Apple Revoke Token endpoint

Open linkillhz opened this issue 2 years ago • 44 comments

Feature proposal

  • Firebase Component: Auth

Apple's new guidelines say, If your app offers sign-in with Apple, you must use sign-in with the Apple REST API to revoke your user token when you delete your account. https://developer.apple.com/news/?id=12m75xbj

Does Firebase Auth offer any functionality to assist with account deletion?

linkillhz avatar Jun 14 '22 05:06 linkillhz

A similar question has been asked on stack overflow. https://stackoverflow.com/questions/72415814/where-i-get-from-ios-firebase-api-the-apple-revoke-tokens-endpoint-parameters-c

linkillhz avatar Jun 14 '22 05:06 linkillhz

Hi @linkillhz -

you can delete user accounts in Firebase Auth using user.delete():

if let user = Auth.auth().currentUser {
  do {
    try await user.delete()
  }
  catch {
    print(error)
  }
}

See the docs for more details.

To delete any of the user's associated data, you can use the Delete User Data Extension. This essentially is a Cloud Function that will run whenever a Firebase Auth user account is deleted (either using the call above or via the Firebase console), and can delete the user's data in Cloud Firestore, Cloud Storage, and the Realtime Database.

If you find that your data model is different from what the Extension currently supports:

  1. Please consider leaving feedback on the Firebase Extensions repo (file a feature request outlining how your data model looks like)
  2. Consider implementing your own Cloud Function based on the code of the Delete User Data Extension

As for revoking the token, @rosalyntan and @renkelvin can provide more details.

peterfriese avatar Jun 14 '22 07:06 peterfriese

Hi, @rosalyntan and @renkelvin

Firebase SDK did not call Apple's revoke token endpoint when I deleted my Firebase account. I have a few questions.

  • What should be the flow for calling Apple's revoke token endpoint when deleting a Firebase account? Do I need to implement my own Cloud Function? Also, can I get the necessary parameters for Apple's revoke token endpoint?

  • Are there any plans to support calling Apple's revoke token endpoint in the Firebase SDK?

Regards

linkillhz avatar Jun 15 '22 06:06 linkillhz

+1 Apple is complaining about this being a requirement June 30th. Looks like apps wont be accepted after that date if they do not delete tokens. This is the message:

Starting June 30, 2022, apps submitted to the App Store that support account creation must also include an option to initiate account deletion.

We noticed this app may support account creation. If it does not, you may disregard this message. If it already offers account deletion or you’re working to implement it, we appreciate your efforts to follow the App Store Review Guidelines. Apps submitted after June 30 that do not comply with the account deletion requirements in guideline 5.1.1(v) will not pass review.

Learn more about the account deletion requirements. If your app offers Sign in with Apple, use the Sign in with Apple REST API to revoke user tokens.

CalHoll avatar Jun 16 '22 23:06 CalHoll

+1 this is a real problem to be addressed before June 30. Either implement it automatically in the SDK (would be great) or give us access to the requested parameters so we can do it ourselves.

Paco777 avatar Jun 17 '22 10:06 Paco777

I don't think it makes sense to offer this with Firebase SDK. This is something the developer has to handle independently with apple auth. You can get the client secrets and token strings during login or sign up. It is decoupled from the Firebase flows.

However, apple has provided very poor documentation for how to implement this. Even if you test their API with something like postman, you will always get status code 200 even with incorrect parameters.

andrejandre avatar Jun 18 '22 15:06 andrejandre

I don't think it makes sense to offer this with Firebase SDK. This is something the developer has to handle independently with apple auth. You can get the client secrets and token strings during login or sign up. It is decoupled from the Firebase flows.

However, apple has provided very poor documentation for how to implement this. Even if you test their API with something like postman, you will always get status code 200 even with incorrect parameters.

Perhaps you could help explain how this could be implemented, for clarity, I'm using Firebase & Flutter, I use Firebase Auth with flutter and sign_in_with_apple to authenticate with Firebase via the method in the documentation: https://firebase.google.com/docs/auth/flutter/federated-auth

To delete my user, the documentation for firebase/flutter states to call user.delete().

This however would cause an app rejection via Apple's new policy. Is your position that users should know to create their own server outside Firebase, track secrets there after authenticating on Firebase, and then call that server to revoke tokens alongside the calls to firebase to delete the authenticated user?

If so where should that be documented and would a cloud function and Firestore be fine to use to keep track of tokens and revoke on delete?

CalHoll avatar Jun 18 '22 18:06 CalHoll

Hi all -

Thanks for raising this issue - we are aware of this and are actively working on a solution. We will update this issue once we can share more details.

Documentation (and accompanying sample code) would definitely be part of the solution. This will likely be a blog post that shows how to use our solution, fast-followed by an update of our docs (https://firebase.google.com/docs/auth/ios/apple).

We would want to avoid developers having to stand up their own servers outside of Firebase - this would defeat the whole purpose of an mBaaS platform.

peterfriese avatar Jun 18 '22 18:06 peterfriese

To @CalHoll,

I would be delighted to know that the proposed solution being worked on by @peterfriese (and the Firebase team) could cover the upcoming requirement.

However, you can see my attempt at this issue here: https://stackoverflow.com/questions/72399534/how-to-make-apple-sign-in-revoke-token-post-request/72488104?noredirect=1#comment128373667_72488104

The general principle of my approach is that I am attempting to perform a POST request with limited understanding of the parameters at play. I have not been able to verify that my solution works when running in a debug environment. To my understanding, I did not think it would have been possible to meet the requirement within the Firebase ecosystem, but will be very pleasantly surprised to be educated otherwise.

andrejandre avatar Jun 20 '22 01:06 andrejandre

Apple's revoke API is called based on JWT signed by the developer's key, so I think it will be difficult for the client to implement the function. I think it's most intuitive to upload a key file from the Firebase console (like cloud messaging) and automatically process it when user.delete(). However, with Apple's instruction request date just around the corner, the way to generate JWT and invoke API via Firebase functions seems not bad.

jooyoungho avatar Jun 20 '22 07:06 jooyoungho

Firebase functions require the Blaze plan, though. My app is small and so far I haven't used Firebase functions, yet. It would be great if we could just upload the JWT file to Firebase and Firebase takes care of the rest after calling delete() on the user account.

ewerspej avatar Jun 20 '22 13:06 ewerspej

For now I'm trying to implement the revocation calls myself, but I can't find a way to get access_token and refresh_token that I need to revoke. Does Firebase allow to get them? Maybe in some delegate calls during authentication?

algrid avatar Jun 20 '22 16:06 algrid

Thanks for working on this Firebase team. I hope the fix and docs come out soon, as June 30 is right around the corner and no new app updates will be accepted without this implemented.

DennisAshford avatar Jun 21 '22 15:06 DennisAshford

I'm also trying to fill in the "token" parameter, The identityToken I get when I try to log in with Firebase But this parameter filling does not work, Trouble Firebase tell me if there is a way to get the token parameters required for Post And what is the parameter type refresh_token or access_token

unity16th30317 avatar Jun 22 '22 05:06 unity16th30317

Hi all -

Thanks for raising this issue - we are aware of this and are actively working on a solution. We will update this issue once we can share more details.

Documentation (and accompanying sample code) would definitely be part of the solution. This will likely be a blog post that shows how to use our solution, fast-followed by an update of our docs (https://firebase.google.com/docs/auth/ios/apple).

We would want to avoid developers having to stand up their own servers outside of Firebase - this would defeat the whole purpose of an mBaaS platform.

Sadly this blog is not very helpful

unity16th30317 avatar Jun 22 '22 05:06 unity16th30317

After getting the appleIDCredential.authorizationCode from the app, you need to get the refresh token through the auth/token API.

The whole process is as follows.

  1. Get authorizationCode from App where user log in.
  2. Get a refresh token with no expiry time using authorizationCode with expiry time.
  3. After saving the refresh token, revoke it when the user leaves the service.

I implemented it in Firebase functions and put the code to be reference on the link below. https://github.com/jooyoungho/apple-token-revoke-in-firebase

If you did it right, it would have disappeared from your device's Settings - Apps using Apple Sign-in.

jooyoungho avatar Jun 22 '22 06:06 jooyoungho

Thanks,it works!

After getting the appleIDCredential.authorizationCode from the app, you need to get the refresh token through the auth/token API.

The whole process is as follows.

  1. Get authorizationCode from App where user log in.
  2. Get a refresh token with no expiry time using authorizationCode with expiry time.
  3. After saving the refresh token, revoke it when the user leaves the service.

I implemented it in Firebase functions and put the code to be reference on the link below. https://github.com/jooyoungho/apple-token-revoke-in-firebase

If you did it right, it would have disappeared from your device's Settings - Apps using Apple Sign-in.

Thanks!!!!! It works!

unity16th30317 avatar Jun 22 '22 10:06 unity16th30317

Is there a general timeframe for when this will be implemented in the Firebase Auth flow? Curious if it is worth putting in the time for a custom solution or just wait for Firebase to implement this.

DennisAshford avatar Jun 23 '22 13:06 DennisAshford

@peterfriese Is there any expected solution within the coming days? June 30th is getting closer and we wouldn't wanna be rejected due the Apple's requirements, and we'd rather not use some cumbersome custom solutions for that.

maor-loora avatar Jun 25 '22 22:06 maor-loora

From collective analysis on https://github.com/invertase/react-native-apple-authentication/issues/282 it appears the only way to do the revoke is to generate a fresh valid authorization code + a fresh JWT built with a client secret that Firebase Auth has already

It is possible to pre-generate and store a JWT locally (in app) with a maximum expiry of 6 months (per documentation) at cost of possible spoofing with exposed JWT plus need to update app periodically or you have a server API somewhere (could be here!) that can take the known secret firebase auth already has to generate the JWT for post to the Apple REST API for token revocation

It does not appear there is any avoiding some user interaction though as I believe you need an authorization code from the Sign In With Apple APIs which is short-lived and based on my understanding of the Firebase Auth APIs, Firebase does not itself maintain a token to revoke?

So if I understand correctly and all the above is correct - the optimization possible here is the elimination of the need for a server by use of some possible new firebase auth API and existing firebase servers, that can generate take a non-expired apple authorization code from a caller (perhaps react-native-apple-authentication, for react-native people) and do the rest (JWT generation, REST API calls). That's definitely useful so I'm interested in a timeline too if possible.

As a library maintainer, it will take me a while to wrap anything that comes up for react-native-firebase and to communicate how to use it for react-native-apple-authentication users

mikehardy avatar Jun 25 '22 22:06 mikehardy

After getting the appleIDCredential.authorizationCode from the app, you need to get the refresh token through the auth/token API.

The whole process is as follows.

  1. Get authorizationCode from App where user log in.
  2. Get a refresh token with no expiry time using authorizationCode with expiry time.
  3. After saving the refresh token, revoke it when the user leaves the service.

I implemented it in Firebase functions and put the code to be reference on the link below. https://github.com/jooyoungho/apple-token-revoke-in-firebase

If you did it right, it would have disappeared from your device's Settings - Apps using Apple Sign-in.

Hey @jooyoungho. I am able to retrieve the appleIDCredential.authorizationCode at signIn/signUp, but how do I retrieve it while the user is already signed in using firebase? The user never goes through ASAuthorizationControllerDelegate if they have already signed in since last time they used the app.

Knapiii avatar Jun 27 '22 11:06 Knapiii

but how do I retrieve it while the user is already signed in using firebase? The user never goes through ASAuthorizationControllerDelegate if they have already signed in since last time they used the app.

@Knapiii You can implement a user-facing 'reauthentication' flow. That way you can require reauthentication prior to displaying the account deletion UI in your application. Doing that effectively requires that the user tap on another Sign In With Apple or Continue With Apple button.

See https://firebase.google.com/docs/auth/ios/apple#reauthentication_and_account_linking for more details. Doing this safely guarantees you will have the sensitive information required to revoke the token without any of it expiring.

Keep in mind, when reading the Firebase account deletion documentation, it can be considered a 'sensitive' action which would require reauthentication. Firebase recommends performing reauthentication for 'sensitive' actions. I think account deletion and revoking the token from Sign in With Apple are considered sensitive with regards to backend services.

andrejandre avatar Jun 27 '22 12:06 andrejandre

Please, Firebase (@peterfriese) , when you implement the solution, make it possible to revoke the Apple token of the user also from a web server, and not only from the app.

I delete the user account from a web server (using this firebase php api https://github.com/kreait/firebase-php), because It does not force the user to re-authentify before account deletion. (I already display 2 confirmations popup in the app, to ensure that the user really wants to delete his account).

Paco777 avatar Jun 27 '22 17:06 Paco777

Hi all,

We are working on a long-term solution that will call Apple's REST API for token revocation when you delete a Firebase user account that was created using Sign in with Apple.

In the meantime, we recommend choosing one of the following approaches:

  1. If your project is on the Blaze plan: implement a Cloud Function for revoking the user's access token, similar to this one.

  2. If your project is on the Spark plan (and you don't want to upgrade to Blaze), follow the steps outlined by Apple in their Apple Developer Forums post "Handling account deletions and revoking tokens for Sign in with Apple":

    • Delete the user's account data from your systems.
    • Direct the user to manually revoke access for your client.
    • Be sure to clearly communicate that all apps associated with your developer account will be revoked for their user account as well.
    • Respond to the credential revoked notification to revert the client to an unauthorized state. [Note: check the forum post for a detailed explanation of why this last step is critically important.]

Since Apple's Delete User Data requirements state that you should delete the user's data from your systems, we expect many of you will either implement their own Cloud Function for deleting the user's data from any Firebase services you use (such as Cloud Firestore, Realtime Database, or Cloud Storage), or use the Delete User Data Extension. In this case, we recommend choosing option 1 above.

As mentioned, we are actively working on a long-term solution that should make the token revocation process a smooth experience. Once we have an implementation that we can share with you, we will update this GitHub issue.


PS: please don't store any sensitive information in UserDefaults - this is not secure.

peterfriese avatar Jun 27 '22 21:06 peterfriese

Thank you for the effort of the Firebase team. We hope to get official support quickly.

If writing Functions code is difficult, please create custom code from the link below. https://jooyoungho.github.io/apple-token-revoke-in-firebase/make-functions/

To keep things as simple as possible, UserDefaults is used in my documentation. As @peterfriese said, it is recommended to store it in a secure DB (Firestore) rather than UserDefaults.

jooyoungho avatar Jun 28 '22 11:06 jooyoungho

Thanks for creating the code generator, @jooyoungho - this looks like a useful resource!

Regarding UserDefaults - I think it would be useful to call this out more prominently in your repo. Storing this in the iOS keychain might be a better option - this is what Apple recommends in Storing Keys in the Keychain, and what Firebase Auth does to store the currently signed in user (we store the Firebase ID token using FIRAuthStoredUserManager)

peterfriese avatar Jun 28 '22 11:06 peterfriese

Hey - I'm trying to follow the steps laid out by @jooyoungho (thanks)

The Apple login wasn't initially set up by me, and oddly I have found that whilst it is enabled in our app identifier, there is no key attached to it.

I assume that means that I need to create one and attach it to the identifier in order to even begin this process?

I'm using react native with @mikehardy's https://github.com/invertase/react-native-apple-authentication

I'm kind of confused as to how the initial dev wasn't required to set this up. Does anyone know what effect (if any) this change might have on our current Apple Sign In Users once released?

Also - after 7 days its worth asking how the Firebase in-house solution is coming along.

Thanks for all your work guys - I'd be totally lost without these threads.

trickeyd avatar Jul 05 '22 11:07 trickeyd

I too did not have a key setup for 'Sign In with Apple' in my developer account and it has always worked for me w/o the key. I followed this example... https://firebase.google.com/docs/auth/ios/apple

I guess I never setup a key because of this instruction from the documentation....

"In the Firebase console, open the Auth section. On the Sign in method tab, enable the Apple provider. If you are only using Sign In with Apple in an app, you can leave the Service ID, Apple Team ID, private key and key ID fields empty."

But since the solution proposed by @jooyoungho (thanks, btw) uses firebase functions (ie, web environment), I think a key is required.

dillydallygames avatar Jul 08 '22 00:07 dillydallygames

@dillydallygames I was puzzled about that difference in reported success / difficulties from others, and your explanation was really clear, thanks for posting that

mikehardy avatar Jul 08 '22 02:07 mikehardy

Is there any kind of updated timeline on this from the Firebase team? As a newer developer, and still working on understanding authorization flows, the manual implementation is proving to be very challenging for me.

DennisAshford avatar Jul 09 '22 05:07 DennisAshford