aboutyou / dart_packages

Dart and Flutter plugins maintained and used by @ABOUTYOU
222 stars 150 forks source link

Connect with Firebase Auth #91

Open britannio opened 4 years ago

britannio commented 4 years ago

intent://callback?${PARAMETERS FROM CALLBACK BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end

Where do I find ${PARAMETERS FROM CALLBACK BODY}? I'm using Firebase Auth not a custom server.

tp commented 4 years ago

I'm using Firebase Auth not a custom server.

Hey,

the above is only needed when using a custom server, which is meant to mean that you should copy over the POST body (that Apple posts to your server) to that query parameter.

For Firebase we don't have documentation, but anecdotally we know that it works 😉

It depends on the type of integration you want to do, but maybe one of the earlier issues around this helps get you started: https://github.com/aboutyou/dart_packages/issues?q=is%3Aissue+firebase

We'd definitely be grateful for a write-up on how to integrate this with Firebase.

I will close this for now. But feel free to reopen if we can help you any further.

britannio commented 4 years ago

The flow should be similar, I expect to use SignInWithApple.getAppleIDCredential to get a AuthorizationCredentialAppleID containing a crucial IdToken which I then supply to Firebase.

FirebaseAuth.instance.signInWithCredential(
    PlatformOAuthCredential(
        providerId: 'apple.com',
        idToken: credential.identityToken,
        rawNonce: nonce,
    ),
);

Inspired by this snippet. https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_auth/firebase_auth_platform_interface/lib/src/types.dart#L162

On that note, should the AuthorizationCredentialAppleID also contain an accessToken?

HenriBeck commented 4 years ago

@britannio I think the accessToken is named authorizationCode in sign in with apple

https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidcredential/3153032-authorizationcode

britannio commented 4 years ago

@britannio I think the accessToken is named authorizationCode in sign in with apple

https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidcredential/3153032-authorizationcode

ah, thanks!

britannio commented 4 years ago

@tp Can we keep this open until a complete solution is found? Firebase provides a call-back URL but I think it's for web purposes and besides that, only the url scheme we define will open the app.

tp commented 4 years ago

@britannio Sure, seems like this is going somewhere :) Then let's use this to get a codesample documenting the flow with Firebase.

HenriBeck commented 4 years ago

@britannio but what's the hold up now? I think the integration with firebase auth should just work as described in the Firebase Auth iOS Apple docs (also on Android it should).

You get the credentials from this plugin and then just give them to firebase so it can create the user in the firebase backend. That should also work for Android, you just need this small server part to redirect back into the app on android.

britannio commented 4 years ago

@HenriBeck Not knowing what to provide to the redirectUri of WebAuthenticationOptions. It's of this form: intent://callback?${PARAMETERS FROM CALLBACK BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end but I'm unaware of what I should replace ${PARAMETERS FROM CALLBACK BODY} with

HenriBeck commented 4 years ago

@britannio The redirectUri shouldn't be intent://callback?${PARAMETERS FROM CALLBACK BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end.

It should be the URL to small server that is needed for android, in the example in the readme it is https://flutter-sign-in-with-apple-example.glitch.me/callbacks/sign_in_with_apple.

This intent:// URL is defined on the server here in line 25 of server.js

britannio commented 4 years ago

@HenriBeck So is the redirectUri expected to accept requests from Apple's servers and redirect them to the intent:// url where they're intercepted by the app?

HenriBeck commented 4 years ago

yes exactly, so when you call getAppleIDCredential we redirect to the apple website and send along the redirectUri.

Once the user has finished authenticating, Apple will redirect to the redirectUri with a POST request. Note that the redirectUri needs to be an https URI, that's why we can't simply directly link into the app. Then on the server part, the user data is received, and you are being redirected to the intent:// URI which in turn is intercepted by the app. The app then returns the data which was in the intent:// URI

DavidCorrado commented 4 years ago

Hello. I was checking out your project and it seems to work with firebase auth. This is my example code for someone who needs this for future reference

Future<FirebaseUser> signInWithApple() async {
    var redirectURL = "https://SERVER_AS_PER_THE_DOCS.glitch.me/callbacks/sign_in_with_apple";
    var clientID = "AS_PER_THE_DOCS";
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        webAuthenticationOptions: WebAuthenticationOptions(
            clientId: clientID,
            redirectUri: Uri.parse(
                redirectURL)));
    final oAuthProvider = OAuthProvider(providerId: 'apple.com');
    final credential = oAuthProvider.getCredential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
    );
    final authResult =
        await SignInUtil.firebaseAuth.signInWithCredential(credential);
    return authResult.user;
  }

As a note I got it working with iOS and Android through firebase.

HenriBeck commented 4 years ago

@DavidCorrado That is great to hear. I will mark this ticket then as documentation so we can write some document where the full integration is explained.

adario commented 4 years ago

Hello. I was checking out your project and it seems to work with firebase auth. This is my example code for someone who needs this for future reference

Future<FirebaseUser> signInWithApple() async {
    var redirectURL = "https://SERVER_AS_PER_THE_DOCS.glitch.me/callbacks/sign_in_with_apple";
    var clientID = "AS_PER_THE_DOCS";
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        webAuthenticationOptions: WebAuthenticationOptions(
            clientId: clientID,
            redirectUri: Uri.parse(
                redirectURL)));
    final oAuthProvider = OAuthProvider(providerId: 'apple.com');
    final credential = oAuthProvider.getCredential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
    );
    final authResult =
        await SignInUtil.firebaseAuth.signInWithCredential(credential);
    return authResult.user;
  }

As a note I got it working with iOS and Android through firebase.

Hello, could you please specify how you did manage to authenticate via Firebase on Android?

The issue here is that the redirect URI provided by Firebase apparently cannot be extended with the "intent://..." part required by Android; however, without the "intent://..." part, the authentication tab remains open on Android, thus stalling the authentication flow.

Note that on iOS, where no "intent://..." is required, authentication via Firebase appears to work perfectly every time.

Thank you, Dario

HenriBeck commented 4 years ago

@adario you will need this small server as described in the README here: https://github.com/aboutyou/dart_packages/tree/master/packages/sign_in_with_apple#server

When you then get back the credentials from our plugin, you can create the user the same way you already do on iOS.

adario commented 4 years ago

@adario you will need this small server as described in the README here: https://github.com/aboutyou/dart_packages/tree/master/packages/sign_in_with_apple#server

When you then get back the credentials from our plugin, you can create the user the same way you already do on iOS.

@HenriBeck I've created the server as described in the README, and I'm passing it in 'redirectUri' — the authentication tab is now dismissed as expected, but authentication fails on Android with this error:

AppleSignIn: Error = PlatformException(ERROR_INVALID_CREDENTIAL, The supplied auth credential is malformed or has expired. [ The audience in ID Token [*.*****.*****] does not match the expected audience. ], null)

(The token above has been redacted.)

HenriBeck commented 4 years ago

@adario I think you put in the wrong identifier when setting up Sign in with Apple on the Firebase website. My guess is that you put in your normal bundle identifier into Firebase Auth and not the correct Service ID you have configured on Apple's side. That's why you get a mismatch.

For more information see this issue: https://github.com/aboutyou/dart_packages/issues/94

adario commented 4 years ago

@HenriBeck Unfortunately that's not the problem, otherwise I wouldn't have written here... Firebase Auth is configured with the service ID in the console, not the bundle ID — I'm only using the bundle ID on iOS, never on Android.

adario commented 4 years ago

@HenriBeck After doing a flutter clean, and without touching anything, it's now working on Android too — I guess a Hot Reload was not enough... ;-)

Any plans to remove the need for the extra server on Android?

Thanks, Dario

HenriBeck commented 4 years ago

@adario There are no plans to remove the extra server as there is no other way to launch the App on Android without it.

Seems weird that a hot reload fixed that particular issue, but it's always required to do a full restart for packages that have native Android/iOS code, which our package has.

adario commented 4 years ago

@HenriBeck Actually, I wrote that a hot reload was not enough — I had to do a flutter clean to get it working. Thanks for the clarification about Android.

gerryau commented 4 years ago

I'm using Firebase Auth not a custom server.

Hey,

the above is only needed when using a custom server, which is meant to mean that you should copy over the POST body (that Apple posts to your server) to that query parameter.

For Firebase we don't have documentation, but anecdotally we know that it works 😉

It depends on the type of integration you want to do, but maybe one of the earlier issues around this helps get you started: https://github.com/aboutyou/dart_packages/issues?q=is%3Aissue+firebase

We'd definitely be grateful for a write-up on how to integrate this with Firebase.

I will close this for now. But feel free to reopen if we can help you any further.

Can you please elaborate a bit about this, where your say: POST body (that Apple posts to your server) to that query parameter

Can you give me some links or some guidance so I can get this package working on Android with firebase.

Thank you

HenriBeck commented 4 years ago

POST body (that Apple posts to your server) to that query parameter

@gerryau The above text refers to the custom server which is needed for Android support as described in the here in the readme.

You will then need to provide the URL to your own server in getAppleIDCredential via the webAuthenticationOptions

gerryau commented 4 years ago

@HenriBeck Okay thanks,

Do I need to use glitch for this or can I use firebase hosting? Are there any guides for doing this with fire base

gerryau commented 4 years ago

@HenriBeck I've setup the server now as per the docs, what's the next step?

intent://callback?${PARAMETERS FROM CALLBACK BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end

What do I put in the ${PARAMATERS FROM CALLBACK BODY} part?

HenriBeck commented 4 years ago

Do I need to use glitch for this or can I use firebase hosting? Are there any guides for doing this with firebase

You don't have to use glitch of course, in the end, it's just a plain HTTP server. But you can't use the Firebase Auth server.

intent://callback?${PARAMETERS FROM CALLBACK BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end

This is part of the server code you can see on the glitch example.

britannio commented 4 years ago

On Android I'm now using the Android Firebase SDK to handle this Plugin: https://github.com/britannio/android_firebase_siwa I just followed https://firebase.google.com/docs/auth/android/apple#handle_the_sign-in_flow_with_the_firebase_sdk

I'd rather use the alternative approach the docs describe and potentially show a web view instead of leaving the app but step 2 requires initiating the auth process yourself and I don't think this package can do that and redirect back into the app to access the tokens without a http server.

HenriBeck commented 4 years ago

@britannio so what's the question/issue? For our package, you will always need this HTTP server to redirect back into the app again.

peterstojanowski commented 4 years ago

Hi guys, has anyone tried using Sign In with Apple with Firebase anonymous accounts? I'm getting an error saying Duplicate credential received. Please try again with a new credential. when trying to link an anonymous account with Apple credentials I used to sign in to my app before. I then need to regenerate credentials in order for this to work. The problem is that the Apple sign in flow will need to be shown again. Here's my code:

Future<AuthCredential> _generateAppleCredential(
      {String baseUrl, String clientId}) async {
    final redirectURL = "https://$baseUrl/signInWithApple";
    final rawNonce = AuthenticationHelper.randomNonceString();
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
      scopes: [AppleIDAuthorizationScopes.email],
      nonce: AuthenticationHelper.toSha256(rawNonce),
      webAuthenticationOptions: WebAuthenticationOptions(
          clientId: clientId, redirectUri: Uri.parse(redirectURL)),
    );
    final oAuthProvider = OAuthProvider(providerId: "apple.com");
    return oAuthProvider.getCredential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
      rawNonce: rawNonce,
    );
  }

  @override
  Future<User> signInWithApple({String baseUrl, String clientId}) async {
    final currentUser = await _auth.currentUser();
    if (currentUser == null) return null;
    final credential = await _generateAppleCredential(
      baseUrl: baseUrl,
      clientId: clientId,
    );
    try {
      final result = await currentUser.linkWithCredential(credential);
      final user = result.user?.user;
      _streamController.sink.add(user);
      return user;
    } on PlatformException catch (e) {
      if (e.code == "ERROR_CREDENTIAL_ALREADY_IN_USE") {
        final result = await _auth.signInWithCredential(credential); // throws an error here
        return result.user?.user;
      } else {
        throw UserError.Unknown;
      }
    }
  }

The way to accomplish this on iOS is that the error returns updated credentials under AuthErrorUserInfoUpdatedCredentialKey which then can be used to sign in without reauthenticating with Apple. Unfortunately, there is nothing similar in Flutter in PlatformException under details (it's null).

neha-madhini commented 4 years ago

In the server.js, in this line- intent://callback?${PARAMETERS FROM CALLBACK BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end

need to change only the package? or if {PARAMETERS FROM CALLBACK BODY} also need to be changed, could you tell me what to be added here?

HenriBeck commented 4 years ago

@neha-madhini you only need to change your package identifier

SoftWyer commented 4 years ago

For anyone else who was getting the following error:

supplied auth credential is malformed, has expired or is not currently supported

Firebase have changed how they do the OAuth authentication with the latest Flutter libraries. The following code contains both the old and new way of creating the credential:

      // This is the section that decodes the session response to retrieve the access and id tokens
      // We can use this to generate an OAuthCredential that can be used with FireBase.
      Map<String, dynamic> appleValidationReponse = jsonDecode(session.body);

      // This no longer works with the latest Firebase Flutter libraries
      // OAuthCredential authCredential = OAuthCredential(
      //   providerId: "apple.com",
      //   signInMethod: "",
      //   idToken: appleValidationReponse['idToken'],
      //   accessToken: appleValidationReponse['accessToken'],
      //   rawNonce: nonce.toString(),
      // );

      final oAuthProvider = OAuthProvider('apple.com');
      final providerCredential = oAuthProvider.credential(
        idToken: appleValidationReponse['idToken'],
        accessToken: appleValidationReponse['accessToken'],
        rawNonce: nonce.toString(),
      );

      // Authenticate with firebase
      UserCredential authResult = await _auth.signInWithCredential(providerCredential);

Full working code example.

MeshkaniMohammad commented 4 years ago

Hello. I was checking out your project and it seems to work with firebase auth. This is my example code for someone who needs this for future reference

Future<FirebaseUser> signInWithApple() async {
    var redirectURL = "https://SERVER_AS_PER_THE_DOCS.glitch.me/callbacks/sign_in_with_apple";
    var clientID = "AS_PER_THE_DOCS";
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        webAuthenticationOptions: WebAuthenticationOptions(
            clientId: clientID,
            redirectUri: Uri.parse(
                redirectURL)));
    final oAuthProvider = OAuthProvider(providerId: 'apple.com');
    final credential = oAuthProvider.getCredential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
    );
    final authResult =
        await SignInUtil.firebaseAuth.signInWithCredential(credential);
    return authResult.user;
  }

As a note I got it working with iOS and Android through firebase.

Is it valid for the newest version of firebase plugin? I just need the functionality for ios. Isn't there any way to use it without Glitch?

HenriBeck commented 4 years ago

@MeshkaniMohammad for iOS you don't need the Glitch server, it is only required for the Android integration.

MeshkaniMohammad commented 4 years ago

@HenriBeck So I just need to register my call back URL as redirectUrl and register it as a returnUrl in this link?

HenriBeck commented 4 years ago

There is no need for a return url on iOS. Just follow the detailed guide in the readme, skip the android and Glitch server part, and it should work.

houdayec commented 4 years ago

Hello. I was checking out your project and it seems to work with firebase auth. This is my example code for someone who needs this for future reference

Future<FirebaseUser> signInWithApple() async {
    var redirectURL = "https://SERVER_AS_PER_THE_DOCS.glitch.me/callbacks/sign_in_with_apple";
    var clientID = "AS_PER_THE_DOCS";
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        webAuthenticationOptions: WebAuthenticationOptions(
            clientId: clientID,
            redirectUri: Uri.parse(
                redirectURL)));
    final oAuthProvider = OAuthProvider(providerId: 'apple.com');
    final credential = oAuthProvider.getCredential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
    );
    final authResult =
        await SignInUtil.firebaseAuth.signInWithCredential(credential);
    return authResult.user;
  }

As a note I got it working with iOS and Android through firebase.

But you are not using Firebase Hosting backend to catch the callback. ("https://xxxproject.web.app/__/auth/handler")

I'm having trouble using Firebase Hosting as handler server, getting the error "The requested action is invalid.".

Does anyone got the same problem? Any help is welcome.

HenriBeck commented 4 years ago

@houdayec it is not supported to use the firebase hosted backend as the callback, see our README for instructions, and an example server which you need to set up to use Android.

houdayec commented 4 years ago

@HenriBeck Thanks for your answer. What is blocking to use Firebase Hosting auth handler?

AlexHartford commented 4 years ago

I have the same question as @houdayec. Setting up a server seems unnecessary.

HenriBeck commented 4 years ago

@houdayec easy: Not everyone is using Firebase. So we need to have an implementation which can be done without requiring a special provider/service.

While you might be using Firebase, plenty of consumers/companies might have other providers or own systems, so they can't/don't want to switch to Firebase.

houdayec commented 4 years ago

@houdayec easy: Not everyone is using Firebase. So we need to have an implementation which can be done without requiring a special provider/service.

While you might be using Firebase, plenty of consumers/companies might have other providers or own systems, so they can't/don't want to switch to Firebase.

Of course not everyone is using Firebase. However, this is the most common / used MBaaS and to me, it should be an option as many people are facing an issue with it. It is not a matter of only providing a solution for Firebase, but also for Firebase. No need to switch for Firebase, it does not make sense. But your packages users might enjoy this feature.

HenriBeck commented 4 years ago

@houdayec in our opinion the Firebase Auth package should do the full Firebase integration for Sign in with Apple on Android. For iOS, they could still refer to our package.

@houdayec you can also use the Firebase Cloud Function to implement the server, so this is technically not a blocker when already using Firebase.

jessp01 commented 4 years ago

Hello @DavidCorrado, all,

Future<FirebaseUser> signInWithApple() async {
    var redirectURL = "https://SERVER_AS_PER_THE_DOCS.glitch.me/callbacks/sign_in_with_apple";
    var clientID = "AS_PER_THE_DOCS";
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        webAuthenticationOptions: WebAuthenticationOptions(
            clientId: clientID,
            redirectUri: Uri.parse(
                redirectURL)));
    final oAuthProvider = OAuthProvider(providerId: 'apple.com');
    final credential = oAuthProvider.getCredential(
      idToken: appleIdCredential.identityToken,
      accessToken: appleIdCredential.authorizationCode,
    );
    final authResult =
        await SignInUtil.firebaseAuth.signInWithCredential(credential);
    return authResult.user;
  }

As a note I got it working with iOS and Android through firebase.

I copied the code as is and added it to sign_in_with_apple/example/lib/main.dart. I set the redirectURL and clientID to the correct values. I verified that a simple CURL request returns correctly:

$ curl -X POST https://PROJECT.glitch.me/callbacks/sign_in_with_apple

returns with:

< HTTP/2 307 < date: Sun, 18 Oct 2020 18:36:16 GMT < content-type: text/plain; charset=utf-8 < content-length: 103 < location: intent://callback?#Intent;package=BUNDLE_ID;scheme=signinwithapple;end < x-powered-by: Express < vary: Accept

I also verified the return URL is correctly configured in the service identifier on Apple's end.

When I invoke signInWithApple(), from Android, I get to the Apple login screen (https://appleid.apple.com/auth..), I am successfully authenticated and asked if I'd like to continue. Upon clicking on Continue (on the Apple page), I briefly see the Android logo and am then navigated to a blank screen with a throbber.

I put a debug print right after the SignInWithApple.getAppleIDCredential() call. I am not getting there.

In the console, I see:

D/SurfaceView(20638): onWindowVisibilityChanged(4) false io.flutter.embedding.android.FlutterSurfaceView{7955dfd V.E...... ........ 0,0-720,1436} of ViewRootImpl@981fa54[MainActivity] D/ViewRootImpl@981fa54MainActivity: Relayout returned: old=[0,0][720,1520] new=[0,0][720,1520] result=0x1 surface={false 0} changed=false D/ViewRootImpl@981fa54MainActivity: stopped(false) old=true D/SurfaceView(20638): windowStopped(false) false io.flutter.embedding.android.FlutterSurfaceView{7955dfd V.E...... ........ 0,0-720,1436} of ViewRootImpl@981fa54[MainActivity] D/ViewRootImpl@981fa54MainActivity: stopped(false) old=false

Until I finally give up and get:

E/flutter (20638): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: SignInWithAppleAuthorizationError(AuthorizationErrorCode.canceled, The user closed the Custom Tab)

Any help would be most appreciated.

Cheers,

HenriBeck commented 4 years ago

@jessp01 is your bundle identifier really plate21, normally it is something like com.company.app

Something weird is going on with the redirect for sure, so I would also suggest logging the redirect uri on the server and see if that looks alright

jessp01 commented 4 years ago

Hi @HenriBeck,

Thanks for your reply. Indeed, my bundle ID is different (that was just a test to see whether I'll get a different response with it). Anyway, I'll add some debug prints in the NodeJS code. I'll update when I have additional findings/arrive at a resolution so that others may also benefit from it.

Thanks again,

mpiparo commented 4 years ago

For anyone using Firebase and not wanting to setup a glitch project to process the callback, you can implement the same functionality of the glitch project using Firebase hosting and cloud functions as follows (using typescript):

in index.ts

import * as functions from 'firebase-functions';
import express = require('express');
import { URLSearchParams } from 'url';

const app = express();
app.use(express.urlencoded({ extended: false }));

process.env.ANDROID_PACKAGE_IDENTIFIER = '<your_android_app_package_id>';

app.post("*/app/callbacks/sign_in_with_apple", (request, response) => {
    const redirect = `intent://callback?${new URLSearchParams(
        request.body
    ).toString()}#Intent;package=${process.env.ANDROID_PACKAGE_IDENTIFIER
        };scheme=signinwithapple;end`;

    console.log(`Redirecting to ${redirect}`);
    response.redirect(307, redirect);
});

exports.app = functions.https.onRequest(app);

in your firebase.json, in hosting section, setup url rewrite to call the function:

...
"hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "/app/**",
        "function": "app"
      }

you can then use the following as a callback from apple-sign-in: https://[firebase project id].web.app/app/callbacks/sign_in_with_apple

you can test with:

curl -X POST -H "Content-Type:application/json" 'https://[firebase project id].web.app/app/callbacks/sign_in_with_apple' -d '{"test":"something"}'

if all is working you should see the following test results:

Temporary Redirect. Redirecting to intent://callback?test=something#Intent;package=[your_android_app_package_id];scheme=signinwithapple;end

When the callback is called from apple, and with your intent properly setup in your AndroidManifest.xml according to package docs: https://pub.dev/packages/sign_in_with_apple, your app's call to SignInWithApple.getAppleIDCredential will get a AuthorizationCredentialAppleID returned with token and auth code that you can use to create a Firebase Auth Credential and sign-in:

final appleUser = await SignInWithApple.getAppleIDCredential(
        scopes: [AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName],
        webAuthenticationOptions: WebAuthenticationOptions(
          clientId: '[your Service ID from Apple Dev setup]',
          redirectUri: Uri.parse('https://[firebase_project_id].web.app/app/callbacks/sign_in_with_apple')),
      );

 final oAuthProvider = firebase_auth.OAuthProvider('apple.com');
 final credential = oAuthProvider.credential(
        accessToken: appleUser.authorizationCode,
        idToken: appleUser.identityToken);

_firebaseAuth.signInWithCredential(credential);

*Be sure to add the callback URL and domain in your Apple Dev account within the Web Authentication Configuration in your Service ID Sign-in-with-Apple config setup).

AlexHartford commented 4 years ago

Thanks, @mpiparo that works. Maybe include these steps along with the steps on glitch? With how common it is to use Firebase with Flutter this would make sense. I am still hoping the Flutterfire team is going to make apple auth on android work out of the box, though.

jesper372 commented 3 years ago

I'm just trying to use Apple sign-in on iOS, along with Firebase. It was only through reading through this issue that it's become clear that I don't need to pay any attention to the instructions about setting up a server - the README does not mention anything about that step being specific to Android. I think it would be helpful if it did.

tstrg commented 3 years ago

Hi @jessp01, I'm curious if you found the solution as I'm facing exactly the same issue.

When I invoke signInWithApple(), from Android, I get to the Apple login screen (https://appleid.apple.com/auth..), I am successfully authenticated and asked if I'd like to continue. Upon clicking on Continue (on the Apple page)

I received the exception from SignInWithApple.getAppleIDCredential(...

SignInWithAppleAuthorizationError(AuthorizationErrorCode.canceled, The user closed the Custom Tab)

The same exception is thrown when I close the Apple login screen manually.

I implemented the firebase function provided by @mpiparo. In the log, I can see the intent link was generated with the user's details.