Flutter Firebase Sign In With Apple Not Working ios - ios

I am trying to set up with apple sign in with the following code. When tapping the button nothing happens.
I get the following error:
NoSuchMethodError (NoSuchMethodError: The method '[]' was called on null.
Receiver: null
Tried calling: []("User"))
The new user appears in firebase authentication but other than that the app does not work.
I have enabled sign in with apple in xcode and on developer.apple.com. I have also tried redownloading my provisioning profiles in xcode but no luck.
I have enabled apple sign in in firebase.
Does anyone know how to fix this?
mixin AuthenticationApple {
static String generateNonce([int length = 32]) {
const charset =
'0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
final random = Random.secure();
return List.generate(length, (_) => charset[random.nextInt(charset.length)])
.join();
}
/// Returns the sha256 hash of [input] in hex notation.
static String sha256ofString(String input) {
final bytes = utf8.encode(input);
final digest = sha256.convert(bytes);
return digest.toString();
}
static Future<User> signInWithApple({BuildContext context}) async {
User user;
// To prevent replay attacks with the credential returned from Apple, we
// include a nonce in the credential request. When signing in with
// Firebase, the nonce in the id token returned by Apple, is expected to
// match the sha256 hash of `rawNonce`.
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
// Request credential for the currently signed in Apple account.
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
nonce: nonce,
);
// Create an `OAuthCredential` from the credential returned by Apple.
final oauthCredential = OAuthProvider('apple.com').credential(
idToken: appleCredential.identityToken,
rawNonce: rawNonce,
);
try {
// Sign in the user with Firebase. If the nonce we generated earlier does
// not match the nonce in `appleCredential.identityToken`, sign in will fail.
final UserCredential userCredential =
await FirebaseAuth.instance.signInWithCredential(oauthCredential);
user = userCredential.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
ScaffoldMessenger.of(context).showSnackBar(
AppWidget.customSnackBar(
content: 'The account already exists with a different credential.',
),
);
} else if (e.code == 'invalid-credential') {
ScaffoldMessenger.of(context).showSnackBar(
AppWidget.customSnackBar(
content: 'Error occurred while accessing credentials. Try again.',
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
AppWidget.customSnackBar(
content: 'Error occurred using Apple Sign-In. Try again.',
),
);
}
return user;
}
}

I just surpassed this issue by using iOS 13.0 for simulator. It seems there's an issue with higher versions when using the simulator but not with physical devices.
You can download and install simulators all the way back to iOS 13.0 (which is the minimum version for Apple Sign-In. In Xcode:
Xcode > Preferences.
Select the "Components" tab.
Mark the simulators you want.
Press "Check and Install Now".

Related

Supabase Auth - redirectTo not working for OAuth

I am switching from Flutter to Supabase and am running into an issue with Authentication. Although I can successfully launch the URL with the correct redirect value, I keep getting redirected to the site URL which should only be used for web, not iOS or Android. Below is the function I am using for Apple but this is happening with all other providers as well.
const isWeb = Platform.OS === "web";
const redirectTo = isWeb
? "https://web.example.com/login-callback/"
: "com.example.react://login-callback/";
export const signInWithApple = async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "apple",
options: {
redirectTo: redirectTo,
},
});
if (error !== null) {
console.log(error?.message);
return "error";
} else {
console.log(data);
Linking.openURL(data.url);
return "success";
}
};
The URL that gets logged before launching is correct, for example, LOG {"provider": "apple", "url": "https://api.example.com/auth/v1/authorize?provider=apple&redirect_to=com.example.react%3A%2F%2Flogin-callback%2F"}, but I always get redirected to something like https://web.example.com/#access_token=*****. I had a similar issue with Flutter, and that was because I had not added the additional redirect in Supabase but I already did that. I also confirmed that I have CFBundleURLSchemes set in the info.plist for iOS but that did not fix it.
IF SELF-HOSTING:
Check that you do not have spaces after commas in ADDITIONAL_REDIRECT_URLS.
Correct ✅ :
ADDITIONAL_REDIRECT_URLS="URL,URL,URL"
Incorrect ❌ :
ADDITIONAL_REDIRECT_URLS="URL, URL, URL"

Capacitor sign in with apple is not working

I am using Capacitor sign in with apple to login with Apple, this is my code:
registerApple(apple: string) {
SignInWithApple.authorize().then(resp => {
this.loginSocial(resp);
console.log("respuesta", resp.response);
if (this.error === true) {
this.activateTabMenu(true);
this.navCtrl.navigateRoot("/home");
} else {
this.register(resp.response, resp.response.user, null, null);
this.user.socialType = apple;
this.viewMode = "view1";
this.progressValue = 0.3;
this.dataDepTp();
}
}).catch((err) => console.log(err));
}
the thing is that when I test it it doesn't work, the Apple GUI doesn't open, and the xcode console prints the next message:
[log] - {"code":"UNIMPLEMENTED"}
I also already enable the Sign In with Apple in xcode and apple developers
what can I do?
Run on physical device or on macOS, iOS has a few issues with this plugin - https://github.com/capacitor-community/apple-sign-in/issues/23
The following example is Capacitor 3/4 related
Signin with apple requires an options field with a nonce.
The example below uses firebase and npm sha.js
Have a look at the https://github.com/capacitor-community/apple-sign-in docs
Also, the Firebase Apple Sign-in Setup guide explains the apple email relay config - https://firebase.google.com/docs/auth/ios/apple?authuser=0&hl=en'
async loginApple() {
if (this.platform.is('capacitor')) {
const rawNonce = 'any random string will do here';
const nonce = shajs('sha256').update(rawNonce).digest('hex');
const options: SignInWithAppleOptions = {
clientId: 'com.example.app',
redirectURI: 'https://your-app-name.firebaseapp.com/__/auth/handler',
scopes: 'email name',
state: '123456',
nonce,
};
try {
const { response } = await SignInWithApple.authorize(options);
console.log('app:auth: loginApple response - ', response);
}
}
}

Sign out from apple using flutter

How can I logout from apple using flutter
I use sign_in_with_apple plugin + when I signin with apple and i try to print email I get null
Future<UserCredential> signInWithApple() async {
// To prevent replay attacks with the credential returned from Apple, we
// include a nonce in the credential request. When signing in with
// Firebase, the nonce in the id token returned by Apple, is expected to
// match the sha256 hash of `rawNonce`.
SharedPreferences prefs=await SharedPreferences.getInstance();
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
// Request credential for the currently signed in Apple account.
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
nonce: nonce,
);
// Create an `OAuthCredential` from the credential returned by Apple.
final oauthCredential = OAuthProvider("apple.com").credential(
idToken: appleCredential.identityToken,
rawNonce: rawNonce,
);
prefs.setString("email", appleCredential.email.toString());
print("hello $appleCredential");
prefs.setString("mode", "apple");
// Sign in the user with Firebase. If the nonce we generated earlier does
// not match the nonce in `appleCredential.identityToken`, sign in will fail.
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context)=>HomePage()), (route) => false);
return await FirebaseAuth.instance.signInWithCredential(oauthCredential);
}

Plugin.FirebaseAuth.FirebaseAuthException: An error occurred when accessing the keychain Xamarin.forms app

I'm using the latest stable package of Plugin.FirebaseAuth (4.1.0). But when I try to call the SignInWithEmailAndPasswordAsync(email, password) when using the iOS simulator. I get an exception?
Method:
public async Task<bool> SignIn(string email, string password)
{
try
{
var result = await CrossFirebaseAuth.Current.Instance.SignInWithEmailAndPasswordAsync(email, password);
var token = await result.User.GetIdTokenAsync(true);
Preferences.Set("MyFirebaseRefreshToken", token);
AccountManager.CurrentUserId = result.User.Uid;
return true;
}
catch (FirebaseAuthException ex)
{
Console.WriteLine(ex.Reason);
await App.Current.MainPage.DisplayAlert($"Alert", (ex.Reason.ToString()), "OK");
return false;
}
}`
Error:
If it only happens to ios, that's maybe because you didn't add the Team ID prefix before your App ID. Like this:
Auth.auth().useUserAccessGroup("XK********.com.matkonit.SharedItems")
You can refer to this page.
Ok So the issue turns out to be with the simulator for iOS.
The fix:
You'll need an apple developer account, and a provisioning profile. You'll also need a custom entitlements.plist

Flutter Sign in with apple failure

i implement sign in with apple on my apps, for some reason my server return error cause username length from sign in with apple didn't meet my condition and i didn't cache the information of the user. After that i update the server to remove username length requirement, but unfortunately user name and email is null? The solution i know is to stop using apple id from setting page on Iphone, is there any other solution from code? here is my code :
AppleSignInButton(
style: ButtonStyle.whiteOutline,
cornerRadius: 8,
type: ButtonType.signIn,
onPressed: () async {
var isConnected = await checkConnection();
if (!isConnected) {
showErrorDialog(message: ErrorMessage.NO_NETWORK);
} else {
final AuthorizationResult result = await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
if (result != null) {
switch (result.status) {
case AuthorizationStatus.authorized:
_loginWithApple(result.credential);
break;
case AuthorizationStatus.cancelled:
break;
case AuthorizationStatus.error:
showErrorDialog(message: result.error.localizedFailureReason);
break;
}
} else {
showErrorDialog(message: result.status.toString(), onTap: (){});
}
}
},)
Apparently Apple provides the fullName and email fields for the first sign in only. These fields will be null for subsequent sign ins.
However, you may opt to get the fullName through appleIDCredential.fullName in didCompleteWithAuthorization delegate method, and update the user's profile yourself.
Source: https://github.com/firebase/firebase-ios-sdk/issues/4393#issuecomment-559012512
Add the dependency to your pubspec.yaml file .
You can get the latest version from https://pub.dev/packages/apple_sign_in
dependencies:
apple_sign_in: ^0.1.0
You can install packages from the command line:
$ flutter pub get
Alternatively, your editor might support flutter pub get like Android Studio and Visual Studio code.
import the “apple_sign_in.dart” to use it’s functionality .
import 'package:apple_sign_in/apple_sign_in.dart';
In initState( ) of Scaffold initialise the Functionality .
if(Platform.isIOS){
//check for ios if developing for both android & ios
AppleSignIn.onCredentialRevoked.listen((_) {
print("Credentials revoked");
});
}
Place the Apple Sign in button Specially provided for this operation .
AppleSignInButton(
style: ButtonStyle.black,
type: ButtonType.continueButton,
onPressed: appleLogIn,
);
Define the appleLogIn( ) method for the sign in functionality
if(await AppleSignIn.isAvailable()) {
//Check if Apple SignIn isn available for the device or not
}else{
print('Apple SignIn is not available for your device');
}
If Available then We can request for login
if(await AppleSignIn.isAvailable()) {
final authorizationResult result = await
AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
}
Handle the result according to your requirement
if(await AppleSignIn.isAvailable()) {
final AuthorizationResult result = await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
switch (result.status) {
case AuthorizationStatus.authorized:
print(result.user);//All the required credentials
case AuthorizationStatus.error:
print("Sign in failed: ${result.error.localizedDescription}");
break;
case AuthorizationStatus.cancelled:
print('User cancelled');
break;
}
}
You can send the credentials to your backend on whatever you want to do .

Resources