The Official Firebase docs say:
...
3.Get a Credential object for the new authentication provider:
// Google Sign-in
final credential = GoogleAuthProvider.credential(idToken: idToken);
// Email and password sign-in
final credential =
EmailAuthProvider.credential(email: emailAddress, password: password);
// Etc.
4.Pass the Credential object to the sign-in user's linkWithCredential() method:
try {
final userCredential = await FirebaseAuth.instance.currentUser
?.linkWithCredential(credential);
} on FirebaseAuthException catch (e) {
// ...
}
I have not found any way to get a credential (more specifically, an AuthCredential
) for Apple, which is needed as an argument to the function:
FirebaseAuth.instance.currentUser.linkWithCredential(AuthCredential credential)
I have found ways to link Google and Facebook accounts to existing accounts on my firebase app by following the above described methods, just couldn't figure out a way to get that credential object for Apple. Here's what I tried:
For Google, there is:
final credential = GoogleAuthProvider.credential(...);
For Facebook, there is:
final credential = FacebookAuthProvider.credential(...);
I could not find this in any docs, I checked, and yes, for Apple there is a similar function:
String accessToken = ? //how do I get this???
final credential = AppleAuthProvider.credential(accessToken);
The problem is, how do I get this accessToken String, which is required as a parameter? I have searched everywhere, and couldn't find a solution.
The only possibility I see now to link an apple account to an existing account on my app, is to:
As of Firebase Auth version 4.4.0, you don't need the Apple credential to link an Apple account. Just call the linkWithProvider
method instead of linkWithCredential
and Firebase will run the Apple sign in flow for you. If you are using Flutter Web, call linkWithPopup
.
try {
//AppleAuthProvider is imported from the firebase_auth package
var appleProvider = AppleAuthProvider();
//shows native UI that asks user to show or hide their real email address
appleProvider.addScope('email'); //this scope is required
//pulls the user's full name from their Apple account
appleProvider.addScope('name'); //this is not required
//runs Apple sign in flow and links the Apple account
final userCredential = await FirebaseAuth.instance.currentUser
?.linkWithProvider(appleProvider);
} on FirebaseAuthException catch (e) {
switch (e.code) {
case "provider-already-linked":
print("The provider has already been linked to the user.");
break;
case "invalid-credential":
print("The provider's credential is not valid.");
break;
case "credential-already-in-use":
print("The account corresponding to the credential already exists, "
"or is already linked to a Firebase User.");
break;
// See the API reference for the full list of error codes.
default:
print("Unknown error.");
}
}
Unfortunately, You cannot force the user to provide you with their real email address when using Apple sign in. However, it is worth noting that the 'private-relay' email generated by Apple can be treated as a real email address in your app. If the user logs out, deletes your app, or switches devices, as long as they login again using the Apple sign in flow, the same 'private-relay' email will be used. All messages you send to that 'private-relay' email will also be redirected by Apple servers to their real email address.
I have used the "the_apple_sign_in" package before. In this package:
String.fromCharCodes(appleIdCredential.authorizationCode!)
.String.fromCharCodes(appleIdCredential!.identityToken!)
.Perhaps you can similarly get the Firebase credential. Also here you can find a sample code with this package:
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<UserModel?> signInWithApple(
{List<Scope> scopes = const [Scope.email, Scope.fullName]}) async {
UserModel userModel;
// 1. perform the sign-in request
final result = await TheAppleSignIn.performRequests(
[AppleIdRequest(requestedScopes: scopes)]);
// 2. check the result
switch (result.status) {
case AuthorizationStatus.authorized:
final appleIdCredential = result.credential;
final oAuthProvider = OAuthProvider("apple.com");
final credential = oAuthProvider.credential(
idToken: String.fromCharCodes(appleIdCredential!.identityToken!),
accessToken:
String.fromCharCodes(appleIdCredential.authorizationCode!),
);
final authResult = await _auth.signInWithCredential(credential);
final firebaseUser = authResult.user;
firebaseUser!.updateDisplayName(
'${appleIdCredential.fullName!.givenName} ${appleIdCredential.fullName!.familyName}');
userModel = UserModel(
uid: firebaseUser.uid,
name: firebaseUser.displayName,
email: firebaseUser.email,
image: firebaseUser.photoURL,
idToken:
String.fromCharCodes(appleIdCredential.authorizationCode!));
return userModel;
case AuthorizationStatus.error:
return null;
case AuthorizationStatus.cancelled:
return null;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With