Sign in With Apple
Flutter bridge to Sign in with Apple.
Supports login via an Apple ID, as well as retrieving credentials saved in the user's keychain.
SignInWithAppleButton(
onPressed: () async {
final credential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
);
print(credential);
// Now send the credential (especially `credential.authorizationCode`) to your server to create a session
// after they have been validated with Apple (see `Integration` section for more information on how to do this)
},
);
Integrating Sign in with Apple goes beyond just adding this plugin to your pubspec.yaml
and using the credential-receiving functions exposed by it.
Once you receive the credentials, they need to be verified with Apple's servers (to ensure that they are valid and really concern the mentioned user) and then a new session should be derived from them in your system.
Your server should then daily verify the session with Apple (via a refresh token it obtained on the initial validation), and revoke the session in your system if the authorization has been withdrawn on Apple's side.
Before you can start integrating (or even testing) Sign in with Apple you need a paid membership to the Apple Developer Program. Sign in with Apple is one of the restricted services which is not available for free with just an Apple ID (source).
If you don't have one yet, create a new one at https://developer.apple.com/account/resources/identifiers/list/bundleId following these steps:
Description
and Bundle ID
, and select the Sign In with Apple
capabilityIn case you already have an existing App ID that you want to use with Sign in with Apple:
If you have change your app's capabilities, you need to fetch the updated provisioning profiles (for example via Xcode) to use the new capabilities.
The Service ID is only needed for a Web or Android integration. If you only intend to integrate iOS you can skip this step.
Go to your apple developer page then "Identifiers" and follow these steps:
Next go to https://developer.apple.com/account/resources/identifiers/list/serviceId and follow these steps:
clientID
Now that the service is created, we have to enable it to be used for Sign in with Apple:
Domains and Subdomains
add the domains of the websites on which you want to use Sign in with Apple, e.g. example.com
. You have to enter at least one domain here, even if you don't intend to use Sign in with Apple on any website.Return URLs
box add the full return URL you want to use, e.g. https://example.com/callbacks/sign_in_with_appleIn order to communicate with Apple's servers to verify the incoming authorization codes from your app clients, you need to create a key at https://developer.apple.com/account/resources/authkeys/list:
Now everything is set up on Apple's developer portal and we can start setting up the server.
The server part is usually integrated into your existing backends, and there are existing packages for most existing programming languages and web frameworks out there.
In order to show how to build a complete example, we set up a example project on Glitch which offers simple and free hosting of a HTTPS-enabled web API, which is exactly what's needed here.
To get started with the Glitch-based example go to the project's page at https://glitch.com/~flutter-sign-in-with-apple-example and click "Remix this". Now you have your own copy of the sample server!
First select the .env
file in the file browser on the left and put in your credentials (these will not be public, but only shared with invited collaborators).
Then click on the "Share" button next to your avatar in the upper left, select "Live App" and copy the entry page URL (e.g. https://some-random-identifier.glitch.me
).
Now update the services you created earlier at https://developer.apple.com/account/resources/identifiers/list/serviceId to include the following URL under Return URLs
: https://[YOUR-PROJECT-NAME].glitch.me/callbacks/sign_in_with_apple
(replacing the name inside the []
).
After this is done, you can now proceed to integrate Sign in with Apple into the code of your Flutter app.
Adding Sign in with Apple to a Flutter app is shown from 2 sides here. First we look into making the example app work with our server-side setup, and then we go over the additional steps required to set up your app from scratch.
To use this plugin on Android, you will need to use the Android V2 Embedding.
You can find out if you are already using the new embedding by looking into your AndroidManifest.xml
and look for the following element:
<meta-data
android:name="flutterEmbedding"
android:value="2"
/>
In case you are not yet using Android V2 Embedding, please first upgrade your app using the following guide: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects
launchMode
To ensure that deep links from the login web page (shown in a Chrome Custom Tab) back to the app still work, your app must use launchMode
singleTask
or singleTop
singleTask
the Chrome Custom Tab persists across app switches from within Android's app switcher, but will be dismissed when the app is launched anew from the home screen icon / app gallerysingleTop
the Chrome Custom Tab stays present both after using the app switcher or launching the app anew via its iconlaunchMode
be sure to test any other third-party integrations that might be affected by this (e.g. deep links)For web support you need to add the follow script import to your index.html
's <head>
tag:
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
(We haven't found a way to only load this on demand, as the script seemingly inits itself on page load.)
Then in the service's configuration in Apple's developer portal add the domains that host your page both in Domains and Subdomains
as well as Returns URLs
.
The former is needed so you can open the flow from the web page, while the latter is used to post the final credentials back from the pop-up to the opening page. (If you omit this, the flow will just silently be stuck in the last step.)
example
folder inside this package in an editor of your choiceflutter packages get
lib/main.dart
and look at the SignInWithAppleButton.onPressed
callbackscopes
parameter to your required scopes, for testing we can keep requesting a name and emailWebAuthenticationOptions
constructor to match the values in the Apple Developer PortalsignInWithAppleEndpoint
variable to point to yourflutter run
the example on an Android device or emulatorIn your android/app/src/main/AndroidManifest.xml
inside <application>
add
<!-- Set up the Sign in with Apple activity, such that it's callable from the browser-redirect -->
<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>
On the Sign in with Apple callback on your server (specified in WebAuthenticationOptions.redirectUri
), redirect safely back to your Android app using the following URL:
intent://callback?${PARAMETERS FROM CALLBACK BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end
The PARAMETERS FROM CALLBACK BODY
should be filled with the urlencoded body you receive on the endpoint from Apple's server, and the package
parameter should be changed to match your app's package identifier (as published on the Google Play Store). Leave the callback
path and signinwithapple
scheme untouched.
Furthermore, when handling the incoming credentials on the client, make sure to only overwrite the current (guest) session of the user once your own server have validated the incoming code
parameter, such that your app is not susceptible to malicious incoming links (e.g. logging out the current user).
At this point you should have added the Sign in with Apple capability to either your own app's capabilities or the test application you created to run the example.
In case you don't have Automatically manage Signing
turned on in Xcode, you will need to recreate and download the updated Provisioning Profiles for your app, so they include the new Sign in with Apple
capability. Then you can download the new certificates and select them in Xcode.
In case XCode manages your signing, this step will be done automatically for you. Just make sure the Sign in with Apple
capability is actived as described in the example below.
Additionally this assumes that you have at least one iOS device registered in your developer account for local testing, so you can run the example on a device.
example
folder in a terminal and run flutter packages get
example/ios/Runner.xcworkspace
in XcodeRunner
(file browser side bar) -> Targets
-> Runner
-> Signing & Capabilities
set the "Bundle Identifier" ("App ID") you have created in the Apple Developer Portal earlier+
)example
folder and execute the follow commandscd ios
bundle install
, to install the Ruby dependencies used for Cocoapodsbundle exec pod install
, to install the Cocoapods for the iOS projectexample
folder and flutter run
on your test deviceRunner
(file browser side bar) -> Targets
-> Runner
-> Signing & Capabilities
), as otherwise Sign in with Apple will fail without visual indication (the code will still receive exceptions)clientID
used when validating the received code
parameter with Apple's server is dependent on the client: Use the App ID (also called "Bundle ID" in some places) when using codes from apps running on Apple platforms, and use the service ID when using a code retrieved from a web authentication flowThe setup for macOS is mostly similar to iOS. As usual for Flutter development for macOS, you must be on the dev
or master
channel.
example
folder in a terminal and run flutter packages get
example/macos/Runner.xcworkspace
in XcodeRunner
(file browser side bar) -> Targets
-> Runner
-> Signing & Capabilities
set the "Bundle Identifier" ("App ID") you have created in the Apple Developer Portal earlier+
)example
folder and flutter run
on your test deviceRun this command:
With Flutter:
$ flutter pub add sign_in_with_apple
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
sign_in_with_apple: ^5.0.0
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import 'dart:io';
// Needed because we can't import `dart:html` into a mobile app,
// while on the flip-side access to `dart:io` throws at runtime (hence the `kIsWeb` check below)
import 'html_shim.dart' if (dart.library.html) 'dart:html' show window;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: ((settings) {
// This is also invoked for incoming deep links
// ignore: avoid_print
print('onGenerateRoute: $settings');
return null;
}),
home: Scaffold(
appBar: AppBar(
title: const Text('Example app: Sign in with Apple'),
),
body: Container(
padding: const EdgeInsets.all(10),
child: Center(
child: SignInWithAppleButton(
onPressed: () async {
final credential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
webAuthenticationOptions: WebAuthenticationOptions(
// TODO: Set the `clientId` and `redirectUri` arguments to the values you entered in the Apple Developer portal during the setup
clientId:
'de.lunaone.flutter.signinwithappleexample.service',
redirectUri:
// For web your redirect URI needs to be the host of the "current page",
// while for Android you will be using the API server that redirects back into your app via a deep link
kIsWeb
? Uri.parse('https://${window.location.host}/')
: Uri.parse(
'https://flutter-sign-in-with-apple-example.glitch.me/callbacks/sign_in_with_apple',
),
),
// TODO: Remove these if you have no need for them
nonce: 'example-nonce',
state: 'example-state',
);
// ignore: avoid_print
print(credential);
// This is the endpoint that will convert an authorization code obtained
// via Sign in with Apple into a session in your system
final signInWithAppleEndpoint = Uri(
scheme: 'https',
host: 'flutter-sign-in-with-apple-example.glitch.me',
path: '/sign_in_with_apple',
queryParameters: <String, String>{
'code': credential.authorizationCode,
if (credential.givenName != null)
'firstName': credential.givenName!,
if (credential.familyName != null)
'lastName': credential.familyName!,
'useBundleId':
!kIsWeb && (Platform.isIOS || Platform.isMacOS)
? 'true'
: 'false',
if (credential.state != null) 'state': credential.state!,
},
);
final session = await http.Client().post(
signInWithAppleEndpoint,
);
// If we got this far, a session based on the Apple ID credential has been created in your system,
// and you can now set this as the app's session
// ignore: avoid_print
print(session);
},
),
),
),
),
);
}
}
Download details:
Author: aboutyou.com
Source: https://github.com/aboutyou/dart_packages