Giter VIP home page Giter VIP logo

Comments (65)

DavidCorrado avatar DavidCorrado commented on May 28, 2024 36

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.

from dart_packages.

mpiparo avatar mpiparo commented on May 28, 2024 16

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).

from dart_packages.

tp avatar tp commented on May 28, 2024 4

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.

from dart_packages.

houdayec avatar houdayec commented on May 28, 2024 4

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

from dart_packages.

alymbouras avatar alymbouras commented on May 28, 2024 3

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).

This one works, thanks!!
Been trying to find a solution everywhere.
Needed to do a couple of changes though.

Need to "Set up Firebase Hosting" first, selecting TypeScript as a language. (go to Firebase -> Hosting, and follow instructions)

firebase login
firebase init firestore
firebase init functions (select Typescript)

When the files are created using the firebase command, copy the code above to the src/index.ts file.
Then run this command to deploy the function:

firebase deploy --only functions

This also created an http Function. (Firebase -> Functions).
Also in my case you the root was app/ so removed the extra app as well, so ended up like this:

app.post("*/callbacks/sign_in_with_apple", (request, response) => {

Run npm run serve while in the functions folder to test it locally:

functions$ npm run serve

Extra steps:

Also added this URL (https://us-central1-{YOUR-FIREBASE-PROJECT}.cloudfunctions.net/app/callbacks/sign_in_with_apple) on my Service ID Identifier from the Apple Developer website.
This was also the redirect URL that I was using in my project.

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024 2

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.

from dart_packages.

AlexHartford avatar AlexHartford commented on May 28, 2024 2

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.

from dart_packages.

gerryau avatar gerryau commented on May 28, 2024 1

@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?

from dart_packages.

jessp01 avatar jessp01 commented on May 28, 2024 1

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,

from dart_packages.

SoftWyer avatar SoftWyer commented on May 28, 2024 1

@angelserranoperez

This is my manifest (same as yours)

manifest
    <!-- Apple sign in -->
    <!-- see https://pub.dev/packages/sign_in_with_apple#-readme-tab -->
    <activity android:name="com.aboutyou.dart_packages.sign_in_with_apple.SignInWithAppleCallback"
      android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="signinwithapple" />
        <data android:path="callback" />
      </intent-filter>
    </activity>

And the server side code to call back to Android, which is mostly the same too.

Server code
// The callback route used for Android, which will send the callback parameters from Apple into the Android app.
// This is done using a deeplink, which will cause the Chrome Custom Tab to be dismissed and providing the parameters from Apple back to the app.
app.post("/callbacks/sign_in_with_apple", (request, response) => {
  console.log(`Request to callbacks`);
  const redirect = `intent://callback?${new URLSearchParams(
    request.body
  ).toString()}#Intent;package=${functions.config().apple.android_package_identifier};scheme=signinwithapple;end`;

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

  response.redirect(307, redirect);
});

from dart_packages.

Parthib avatar Parthib commented on May 28, 2024 1

I made a dead simple python script for AWS Lambda (+ API Gateway) that does the redirect magic in case it helps anyone:

import json
import base64

def lambda_handler(event, context):
    print(event)
    redirectActivityIdentifier = 'com.example.app'
    redirectData = base64.b64decode(event['body']).decode('ascii')
    
    redirect = f"intent://callback?{redirectData}#Intent;package={redirectActivityIdentifier};scheme=signinwithapple;end"
    
    print(f"redirecting to {redirect}")
    
    return {
        'statusCode': 307,
        'headers': {'Location': redirect},
        'body': json.dumps({})
    }

Got Apple login through Firebase working on Android (can't seem to get Apple login to work on my iOS simulator funnily enough because of https://developer.apple.com/forums/thread/651533?page=10).

from dart_packages.

Mikelcastrolads avatar Mikelcastrolads commented on May 28, 2024 1

Hi @tstrg,

May I ask what's your solution to your error?

Because my error is the same as yours. I'm able to authenticate but when I clicked continue it redirects to my app in playstore and when I open it the error shows:

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

from dart_packages.

britannio avatar britannio commented on May 28, 2024

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?

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

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

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

from dart_packages.

britannio avatar britannio commented on May 28, 2024

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

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

ah, thanks!

from dart_packages.

britannio avatar britannio commented on May 28, 2024

@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.

from dart_packages.

tp avatar tp commented on May 28, 2024

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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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.

from dart_packages.

britannio avatar britannio commented on May 28, 2024

@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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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

from dart_packages.

britannio avatar britannio commented on May 28, 2024

@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?

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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.

from dart_packages.

adario avatar adario commented on May 28, 2024

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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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.

from dart_packages.

adario avatar adario commented on May 28, 2024

@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.)

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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: #94

from dart_packages.

adario avatar adario commented on May 28, 2024

@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.

from dart_packages.

adario avatar adario commented on May 28, 2024

@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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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.

from dart_packages.

adario avatar adario commented on May 28, 2024

@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.

from dart_packages.

gerryau avatar gerryau commented on May 28, 2024

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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

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

from dart_packages.

gerryau avatar gerryau commented on May 28, 2024

@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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

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.

from dart_packages.

britannio avatar britannio commented on May 28, 2024

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.

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

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

from dart_packages.

peterstojanowski avatar peterstojanowski commented on May 28, 2024

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).

from dart_packages.

neha-madhini avatar neha-madhini commented on May 28, 2024

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?

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

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

from dart_packages.

SoftWyer avatar SoftWyer commented on May 28, 2024

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.

from dart_packages.

MeshkaniMohammad avatar MeshkaniMohammad commented on May 28, 2024

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?

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

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

from dart_packages.

MeshkaniMohammad avatar MeshkaniMohammad commented on May 28, 2024

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

from dart_packages.

houdayec avatar houdayec commented on May 28, 2024

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.

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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.

from dart_packages.

AlexHartford avatar AlexHartford commented on May 28, 2024

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

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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.

from dart_packages.

houdayec avatar houdayec commented on May 28, 2024

@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.

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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.

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

@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

from dart_packages.

jessp01 avatar jessp01 commented on May 28, 2024

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,

from dart_packages.

jesper372 avatar jesper372 commented on May 28, 2024

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.

from dart_packages.

tstrg avatar tstrg commented on May 28, 2024

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.

from dart_packages.

SoftWyer avatar SoftWyer commented on May 28, 2024

@tstrg Just tried this with my Android app and signing in via apple and it worked OK.

The code I used can be viewed in this Gtihub repo. It might offer some clues as to why yours failed.

I did need another apple device (mac or phone) to validate the 2FA so perhaps this also needs setting up on your apple account?

from dart_packages.

tstrg avatar tstrg commented on May 28, 2024

@SoftWyer I've given it third try. I started from scratch and it starts working. Thanks for the code example.

from dart_packages.

angelserranoperez avatar angelserranoperez commented on May 28, 2024
<activity
    android:name="com.aboutyou.dart_packages.sign_in_with_apple.SignInWithAppleCallback"
    android:exported="true"
>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="signinwithapple" />
        <data android:path="callback" />
    </intent-filter>
</activity>

I have the same situation that this guy but I implemented the firebase cloud function (I check the result and I get the correct intent sintaxt callback):
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 think that I do not configure well the intent on ANDROID:
Some questions:
android:name="com.aboutyou.dart_packages.sign_in_with_apple.SignInWithAppleCallback"
has it to be this name or I have to change it? ...

Some one succesfull can share how he or she implement the intent on ANDROID...

Thank You

from dart_packages.

britannio avatar britannio commented on May 28, 2024

I made a dead simple python script for AWS Lambda (+ API Gateway) that does the redirect magic in case it helps anyone:

import json
import base64

def lambda_handler(event, context):
    print(event)
    redirectActivityIdentifier = 'com.example.app'
    redirectData = base64.b64decode(event['body']).decode('ascii')
    
    redirect = f"intent://callback?{redirectData}#Intent;package={redirectActivityIdentifier};scheme=signinwithapple;end"
    
    print(f"redirecting to {redirect}")
    
    return {
        'statusCode': 307,
        'headers': {'Location': redirect},
        'body': json.dumps({})
    }

Got Apple login through Firebase working on Android (can't seem to get Apple login to work on my iOS simulator funnily enough because of https://developer.apple.com/forums/thread/651533?page=10).

A Dart cloud functions solution would be handy for anyone using FIrebase as Firebase projects are tied to a Google Cloud project. https://dart.dev/server/google-cloud#functions-framework-for-dart

from dart_packages.

HenriBeck avatar HenriBeck commented on May 28, 2024

Note that the documentation for macOS/iOS can be found here: https://firebase.flutter.dev/docs/auth/social/#apple

Note that Android would work the same as long as you still use the redirect handler described in our README and not the one from Firebase.

from dart_packages.

ZahraVe avatar ZahraVe commented on May 28, 2024

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

*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).

Could you please explain how should I run curl -X POST -H "Content-Type:application/json" 'https://[firebase project id].web.app/app/callbacks/sign_in_with_apple' -d '{"test":"something"}' I am new in backend, I am using flutter and firestore, I made sure to have cloud_function and cloud_firestore packages and also linked my project to the backend and see { "projects": { "default": "<YOUR_FIREBASE_PROJECT_ID>" } }
Appreciate any suggestion.

from dart_packages.

MarkJocas avatar MarkJocas commented on May 28, 2024

Hi @tstrg,

May I ask what's your solution to your error?

Because my error is the same as yours. I'm able to authenticate but when I clicked continue it redirects to my app in playstore and when I open it the error shows:

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

After setting all the Services IDs (don't forget to set that on Firebase Authentication for Apple page) and subdomains / URLs for firebase functions redirects, I also reach the redirect to playstore page not found.

Could this be something browser specific, which doesn't take my back to the fapp?

from dart_packages.

ZahraVe avatar ZahraVe commented on May 28, 2024

After entering the Apple ID and password, I cannot redirect to the app.

@alymbouras
Thanks for explaining these additional steps. I followed the steps and reached the point where I entered the Apple ID and password. But after continuing the process, I get an infinite circular indicator on a white screen of the google play store. It doesn't direct me to the app. I am on debug mode and also have tested the callback :
Temporary Redirect. Redirecting to intent://callback?key=value#Intent;package=com.example.backend_test_app;scheme=signinwithapple;end%
Any idea to fix this would be appreciated!

from dart_packages.

ZahraVe avatar ZahraVe commented on May 28, 2024

@alymbouras

URL (https://us-central1-{YOUR-FIREBASE-PROJECT}.cloudfunctions.net/app/callbacks/sign_in_with_apple)

I am wondering if your deployed Function URL in Firebase if it includes "/callbacks/sign_in_with_apple" or not? I am using JavaScript so I converted the index.ts to index.js. I am not sure if this might cause the issues I mentioned at #91 (comment) or not!

from dart_packages.

ZahraVe avatar ZahraVe commented on May 28, 2024

@jessp01

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.

@angelserranoperez
I am facing the same problem with sign-in with Apple on android using firebase functions.
I am wondering if you have found any solution?!

from dart_packages.

chadlyalan avatar chadlyalan commented on May 28, 2024

Is there any documentation of steps for using Web only?

When I run in Debug the Sign In with Apple button opens a pop-up that says "invalid_request" "Invalid web redirect url." But the same code deployed to firebase does nothing but throw's an error in the console: "Uncaught Unsupported operation: Platform._operatingSystem"

Anyone run into this that could point me in the right direction?

My Flutter code looks identical to the Example code here with the obvious exception being the clientId is the Service ID identifier that has "sign in with apple" configured on it.

from dart_packages.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.