Flutter Apple Sign In with Firebase Authentication for iOS and Android

varun wani
4 min readSep 26, 2022

Signing in to the system is important part of development. There are various ways to get into it. We are exploring Apple Signin with firebase authentication.

In this post, we are going to add Apple Sign In to our Flutter & Firebase application. We will use the sign_in_with_apple Flutter package available on pub.dev.

Requirements

  1. Xcode installed
  2. An Apple Developer Account
  3. An iOS 13.x device or simulator, signed in with an Apple ID
  4. Firebase Project for the App

Firebase Setup

We need to register iOS App to the Firebase project. Please remember the bundle ID as we are going to use to later on.

Download the GoogleService-Info.plist file

Enable Apple authentication

Apple Setup

  1. Open the Identifiers page on the Apple developer website and click the (+) icon.
  2. Select App IDs and click on Continue.
  3. Then select the type of App. Click on Continue.
  4. Set the bundle ID same as we used in the firebase project. Check on the Sign In with Apple capability, then select Continue.
  5. Click onRegister to complete Apple configuration.

Project Setup

  1. Create the project of flutter
  2. Update pubspec.yaml with below to add the required packages

3. Open same project in Xcode.

4. On the Signing & Capabilities tab, configure the signing by setting the Team as per your Apple developer account. Make sure to use the same bundle ID we used in the firebase project.

5. Add “Sign In With Apple” as a new Capability

6. Set the Deployment target to iOS 13

Application Implementation

You can check the implementation part on https://github.com/varunwani22/Flutter_Projects/tree/master/apple_signin

AuthenticationProvider.dartimport 'dart:convert';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
class AuthenticationProvider with ChangeNotifier {
final FirebaseAuth _firebaseAuth;
AuthenticationProvider(this._firebaseAuth);Stream<User?> get authStateChanges => _firebaseAuth.authStateChanges();Future<void> signOut() async {await _firebaseAuth.signOut();}/// Generates a cryptographically secure random nonce, to be included in a/// credential request.String generateNonce([int length = 32]) {
final 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.String sha256ofString(String input) {
final bytes = utf8.encode(input);
final digest = sha256.convert(bytes);
return digest.toString();
}
Future<User?> signInWithApple() async {// To prevent replay attacks with the credential returned from Apple, we// include a nonce in the credential request. When signing in 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);
var redirectUri = "";
var clientId = "";
try {
// Request credential for the currently signed in Apple account.
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
webAuthenticationOptions: WebAuthenticationOptions(
clientId: clientId, redirectUri: Uri.parse(redirectUri)),
nonce: nonce,
;
print(appleCredential.authorizationCode);// Create an `OAuthCredential` from the credential returned by Apple.final oauthCredential = OAuthProvider("apple.com").credential(idToken: appleCredential.identityToken,
rawNonce: rawNonce,
);
// 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 authResult =await _firebaseAuth.signInWithCredential(oauthCredential);final displayName ='${appleCredential.givenName} ${appleCredential.familyName}';final userEmail = '${appleCredential.email}';
final firebaseUser = authResult.user;
print(displayName);
await firebaseUser?.updateProfile(displayName: displayName);
await firebaseUser?.updateEmail(userEmail);
return firebaseUser;
} catch (exception) {
print(exception);
}
}
}
main.dart
import package:apple_signin/providers/authentication_provider.dart';
import 'package:apple_signin/screens/login_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:provider/provider.dart';
import 'screens/logout_screen.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {// This widget is the root of your application.@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => AuthenticationProvider(FirebaseAuth.instance),
),
StreamProvider(
create: (BuildContext context) {
return context.read<AuthenticationProvider>().authStateChanges;
},
initialData: null,
)
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
visualDensity: VisualDensity.adaptivePlatformDensity,),
home: MyHomePage(),),
);
}
}
class MyHomePage extends StatelessWidget {@override
Widget build(BuildContext context) {
final firebaseUser = context.watch<User>();
return Scaffold(appBar: AppBar(title: Text('Apple Sign In'),),body: firebaseUser != null ? LogoutPage() : LoginPage());}}login_page.dart
import 'package:apple_signin/providers/authentication_provider.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
class LoginPage extends StatelessWidget {@override
Widget build(BuildContext context) {
return Scaffold(body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SignInWithAppleButton(
style: SignInWithAppleButtonStyle.black,
iconAlignment: IconAlignment.center,
onPressed: () {
context.read<AuthenticationProvider>().signInWithApple();
},
),
],
),
),
);
}
}
logout_page.dart
import
'package:apple_signin/providers/authentication_provider.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class LogoutPage extends StatelessWidget {@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: RaisedButton(
onPressed: () {
context.read<AuthenticationProvider>().signOut();
},
child: Text("Sign out"),
),
),
],
),
),
);
}
}

Where the package supports the platforms like iOS, macOS, Android, Web.

For that we need to specify few additional things like serviceID on firebase.

And redirectUri, clientId in webAuthenticationoptions

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

varun wani
varun wani

Written by varun wani

Passionate android developer, in learning phase. Always interested in learning new things

No responses yet

Write a response