docs: update Flutter docs/ guides/ examples to reflect the new Skip nonce checks option for Google login (#18697)

* update example google sign in app

* update flutter google sign in example

* update flutter auth blog post to add skip nonce check content

* update google sign in guide to include skip nonce check content

* minor update on the code sample for google auth guide

* delete unused code from code sample

* minor update of the blog writing

* blog article refactor

* minor format fix

* Update apps/docs/pages/guides/auth/social-login/auth-google.mdx

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* Update apps/docs/pages/guides/auth/social-login/auth-google.mdx

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* Update apps/docs/pages/guides/auth/social-login/auth-google.mdx

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* Update apps/www/_blog/2023-07-18-flutter-authentication.mdx

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* Update apps/www/_blog/2023-07-18-flutter-authentication.mdx

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* Update apps/www/_blog/2023-07-18-flutter-authentication.mdx

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* Update apps/www/_blog/2023-07-18-flutter-authentication.mdx

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* fix typo

---------

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>
This commit is contained in:
TylerandCharis authored and GitHub committed 2023-11-04 06:26:06 +00:00
1 parent 677cec3a70
commit 1a0d92ba41
12 files changed
+250 -520

No files matched your search

@@ -234,130 +234,66 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf
## Using Native Sign in with Google in Flutter
Native Google sign in with Supabase is done through [flutter_appauth](https://pub.dev/packages/flutter_appauth) package for iOS and [google_sign_in](https://pub.dev/packages/google_sign_in) package for Android.
Native Google sign in with Supabase is done through the [google_sign_in](https://pub.dev/packages/google_sign_in) package for iOS and Android. Follow the instructions on the [google_sign_in](https://pub.dev/packages/google_sign_in) package for plugin specific settings.
When the user provides consent, Google issues an identity token (commonly abbreviated as ID token) that is then sent to your project's Supabase Auth server. When valid, a new user session is started by issuing an access and refresh token from Supabase Auth.
If you are building a Flutter app, you can use the [google_sign_in](https://pub.dev/packages/google_sign_in) package for Android and [flutter_appauth](https://pub.dev/packages/flutter_appauth) package for iOS to sign a user into your Supabase project:
Follow the code sample below to implement native Google sign in with Supabase in your Flutter app.
```dart
import 'dart:convert';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:flutter_appauth/flutter_appauth.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
/// Function to generate a random 16 character string.
String _generateRandomString() {
final random = Random.secure();
return base64Url.encode(List<int>.generate(16, (_) => random.nextInt(256)));
}
...
Future<AuthResponse> signInWithGoogle() {
/// TODO: update the iOS and Web client ID with your own.
Future<AuthResponse> _googleSignIn() async {
/// TODO: update the Web client ID with your own.
///
/// Client ID that you registered with Google Cloud.
/// Note that in order to perform Google sign in on Android, you need to
/// provide the web client ID, not the Android client ID.
final clientId = Platform.isIOS ? 'IOS_CLIENT_ID' : 'WEB_CLIENT_ID';
/// Web Client ID that you registered with Google Cloud.
const webClientId = 'my-web.apps.googleusercontent.com';
late final String? idToken;
late final String? accessToken;
String? rawNonce;
/// TODO: update the iOS client ID with your own.
///
/// iOS Client ID that you registered with Google Cloud.
const iosClientId = 'my-ios.apps.googleusercontent.com';
// Use AppAuth to perform Google sign in on iOS
// and use GoogleSignIn package for Google sign in on Android
if (Platform.isIOS) {
const appAuth = FlutterAppAuth();
// Google sign in on Android will work without providing the Android
// Client ID registered on Google Cloud.
// Just a random string
rawNonce = _generateRandomString();
final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString();
final GoogleSignIn googleSignIn = GoogleSignIn(
clientId: iosClientId,
serverClientId: webClientId,
);
final googleUser = await googleSignIn.signIn();
final googleAuth = await googleUser!.authentication;
final accessToken = googleAuth.accessToken;
final idToken = googleAuth.idToken;
/// Set as reversed DNS form of Google Client ID + `:/` for Google login
final redirectUrl = '${clientId.split('.').reversed.join('.')}:/';
/// Fixed value for google login
const discoveryUrl =
'https://accounts.google.com/.well-known/openid-configuration';
// authorize the user by opening the concent page
final result = await appAuth.authorize(
AuthorizationRequest(
clientId,
redirectUrl,
discoveryUrl: discoveryUrl,
nonce: hashedNonce,
scopes: [
'openid',
'email',
'profile',
],
),
);
if (result == null) {
throw 'No result';
}
// Request the access and id token to google
final tokenResult = await appAuth.token(
TokenRequest(
clientId,
redirectUrl,
authorizationCode: result.authorizationCode,
discoveryUrl: discoveryUrl,
codeVerifier: result.codeVerifier,
nonce: result.nonce,
scopes: [
'openid',
'email',
],
),
);
accessToken = tokenResult?.accessToken;
idToken = tokenResult?.idToken;
} else {
final GoogleSignIn googleSignIn = GoogleSignIn(
serverClientId: clientId,
scopes: [
'openid',
'email',
],
);
final googleUser = await googleSignIn.signIn();
final googleAuth = await googleUser!.authentication;
accessToken = googleAuth.accessToken;
idToken = googleAuth.idToken;
}
if (idToken == null) {
throw 'No ID Token';
}
if (accessToken == null) {
throw 'No Access Token';
throw 'No Access Token found.';
}
if (idToken == null) {
throw 'No ID Token found.';
}
return supabase.auth.signInWithIdToken(
provider: Provider.google,
idToken: idToken,
accessToken: accessToken,
nonce: rawNonce,
);
}
...
```
### Configuration [#flutter-configuration-native-app]
1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. When creating a new OAuth client ID, choose _Android_ or _iOS_ depending on the mobile operating system your app is built for.
1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. When creating a new OAuth client ID, choose _Android_ or _iOS_ depending on the mobile operating system your app is built for. Also create a web client ID.
- For Android, use the instructions on screen to provide the SHA-1 certificate fingerprint used to sign your Android app. You also need to create a web client ID to perform Google sign in on Android.
- For iOS, use the instructions on screen to provide the app Bundle ID, and App Store ID and Team ID if the app is already published on the Apple AppStore.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
3. Finally, add the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_. You do not need to add the Android or iOS client ID here. If you need iOS support, enable the `Skip nonce check` option.
Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in.
@@ -411,8 +347,8 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf
1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. When creating a new OAuth client ID, choose _Android_ or _iOS_ depending on the mobile operating system your app is built for.
- For Android, use the instructions on screen to provide the SHA-1 certificate fingerprint used to sign your Android app.
- For iOS, use the instructions on screen to provide the app Bundle ID, and App Store ID and Team ID if the app is already published on the Apple AppStore.
- For Android, use the instructions on screen to provide the SHA-1 certificate fingerprint used to sign your Android app.
- For iOS, use the instructions on screen to provide the app Bundle ID, and App Store ID and Team ID if the app is already published on the Apple AppStore.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
@@ -52,45 +52,49 @@ flutter create myauthapp
then we can install the dependencies. Change the working directory to the newly created app directory and run the following command to install our dependencies.
```dart
flutter pub add supabase_flutter flutter_appauth crypto google_sign_in
flutter pub add supabase_flutter google_sign_in
```
We will use [supabase_flutter](https://pub.dev/packages/supabase_flutter) to interact with our Supabase instance. [google_sign_in](https://pub.dev/packages/google_sign_in) will be used to authenticate on Android, and [flutter_appauth](https://pub.dev/packages/flutter_appauth) will be used for iOS. [crypto](https://pub.dev/packages/crypto) is a library that has utility functions for encryption that we will use when performing OIDC logins.
The [supabase_flutter](https://pub.dev/packages/supabase_flutter) package is used to interact with a Supabase instance. The [google_sign_in](https://pub.dev/packages/google_sign_in) package is used to implement social sign-in with Google.
We are done installing our dependencies. Let’s set up [authentication](https://supabase.com/docs/guides/auth) now.
## Configure Google sign-in on Supabase Auth
We will obtain client IDs for iOS, Android, and web from the Google Cloud console, and register them to our Supabase project.
We need the web client ID in order to use the Google sign-in flow on Android.
The web client ID will be used by the auth server of Supabase to verify the ID token provided by the Google sign-in package.
First, create your Google Cloud project [here](https://cloud.google.com/) if you do not have one yet.
Within your Google Cloud project, follow the [Get an OAuth client ID for the iOS](https://developers.google.com/identity/sign-in/ios/start-integrating#get_an_oauth_client_id) guide, [Configure a Google API Console project for Android](https://developers.google.com/identity/sign-in/android/start-integrating#configure_a_project) guide, and [Get your backend server's OAuth 2.0 client ID](https://developers.google.com/identity/sign-in/android/start-integrating#configure_a_project) to obtain client IDs for iOS, Android, and web respectively.
Once you have the client IDs, let’s add them to our Supabase dashboard. If you don’t have a Supabase project created yet, you can create one at [database.new](https://database.new) for free. The name is just an internal name, so we can call it “Auth” for now. Database Password will not be used in this example and can be reconfigured later, so press the `Generate a password` button and let Supabase generate a secure random password. No need to copy it anywhere. The region should be anywhere close to where you live, or where your users live in an actual production app.
Once you have the client IDs, let’s add them to our Supabase dashboard. If you don’t have a Supabase project created yet, you can create one at [database.new](https://database.new) for free. The name is just an internal name, so we can call it “Auth” for now.
The database password won't be used in this example and can be reconfigured later, so press the `Generate a password` button and let Supabase generate a secure random password. The region should be anywhere close to where you live, or where your users live in an actual production app.
Lastly, for the pricing plan choose the free plan that allows you to connect with all major social OAuth providers and supports up to 50,000 monthly active users.
![Supabase project creation](/images/blog/flutter-authentication/supabase-project-creation.png)
Your project should be ready in a minute or two. Once your project is ready, you can open `authentication -> Providers -> Google` to set up Google auth. Toggle the `Enable Sign in with Google` switch first. Then add the two client IDs you obtained in your Google Cloud console to `Authorized Client IDs` field with a comma in between the two client IDs like this: `IOS_CLIENT_ID,ANDROID_CLIENT_ID,WEB_CLIENT_ID`.
Your project should be ready in a minute or two. Once your project is ready, open `authentication -> Providers -> Google` to set up Google auth. Toggle the `Enable Sign in with Google` switch first. Then add the web client ID you obtained in your Google Cloud console to `Authorized Client IDs` field. No need to add the Android or iOS client IDs here.
Turn on the `Skip nonce checks` option. This would allow us to use the Google sign in package on iOS, which is not compatible with providing a method to access or specify a nonce.
![Supabase auth Google auth provider](/images/blog/flutter-authentication/supabase-google-provider.png)
We also need some Android specific settings to make [flutter_appauth](https://pub.dev/packages/flutter_appauth#android-setup) not throw during app building. Open `android/app/build.gradle` and find the `defaultConfig`. We need to to provide an empty string here.
We also need some iOS specific settings. Open `ios/Runner/Info.plist` file and add the `CFBundleURLTypes` like the following. You need to provide the reverse client ID of the iOS client ID you registered earlier.
```groovy
...
android {
...
defaultConfig {
...
// We need an empty manifestPlaceholders for appauth to not throw an error
manifestPlaceholders += [
'appAuthRedirectScheme': ''
]
}
}
```plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>com.googleusercontent.apps.my-ios</string>
</array>
</dict>
</array>
```
That is it for setting up our [Supabase auth to prepare for Google sign-in](https://supabase.com/docs/guides/auth/social-login/auth-google?platform=flutter).
@@ -140,13 +144,7 @@ You can find your Supabase URL and Anon key in `Settings -> API` from your [Supa
We will have two screens for this app, `LoginScreen` and `ProfileScreen`. `LoginScreen` presents a single sign-in button for the user to perform Google sign-in. Create a `lib/screens/login_screen.dart` file add add the following.
```dart
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:flutter_appauth/flutter_appauth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:myauthapp/main.dart';
import 'package:myauthapp/screens/profile_screen.dart';
@@ -179,103 +177,40 @@ class _LoginScreenState extends State<LoginScreen> {
});
}
/// Function to generate a random 16 character string.
String _generateRandomString() {
final random = Random.secure();
return base64Url.encode(List<int>.generate(16, (_) => random.nextInt(256)));
}
Future<AuthResponse> _googleSignIn() async {
/// TODO: update the iOS and Web client ID with your own.
/// TODO: update the Web client ID with your own.
///
/// Client ID that you registered with Google Cloud.
/// Note that in order to perform Google sign in on Android, you need to
/// provide the web client ID, not the Android client ID.
final clientId = Platform.isIOS ? 'IOS_CLIENT_ID' : 'WEB_CLIENT_ID';
/// Web Client ID that you registered with Google Cloud.
const webClientId = 'my-web.apps.googleusercontent.com';
late final String? idToken;
late final String? accessToken;
String? rawNonce;
/// TODO: update the iOS client ID with your own.
///
/// iOS Client ID that you registered with Google Cloud.
const iosClientId = 'my-ios.apps.googleusercontent.com';
// Use AppAuth to perform Google sign in on iOS
// and use GoogleSignIn package for Google sign in on Android
if (Platform.isIOS) {
const appAuth = FlutterAppAuth();
// Google sign in on Android will work without providing the Android
// Client ID registered on Google Cloud.
// Just a random string
rawNonce = _generateRandomString();
final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString();
final GoogleSignIn googleSignIn = GoogleSignIn(
clientId: iosClientId,
serverClientId: webClientId,
);
final googleUser = await googleSignIn.signIn();
final googleAuth = await googleUser!.authentication;
final accessToken = googleAuth.accessToken;
final idToken = googleAuth.idToken;
/// Set as reversed DNS form of Google Client ID + `:/` for Google login
final redirectUrl = '${clientId.split('.').reversed.join('.')}:/';
/// Fixed value for google login
const discoveryUrl =
'https://accounts.google.com/.well-known/openid-configuration';
// authorize the user by opening the concent page
final result = await appAuth.authorize(
AuthorizationRequest(
clientId,
redirectUrl,
discoveryUrl: discoveryUrl,
nonce: hashedNonce,
scopes: [
'openid',
'email',
'profile',
],
),
);
if (result == null) {
throw 'No result';
}
// Request the access and id token to google
final tokenResult = await appAuth.token(
TokenRequest(
clientId,
redirectUrl,
authorizationCode: result.authorizationCode,
discoveryUrl: discoveryUrl,
codeVerifier: result.codeVerifier,
nonce: result.nonce,
scopes: [
'openid',
'email',
],
),
);
accessToken = tokenResult?.accessToken;
idToken = tokenResult?.idToken;
} else {
final GoogleSignIn googleSignIn = GoogleSignIn(
serverClientId: clientId,
scopes: [
'openid',
'email',
],
);
final googleUser = await googleSignIn.signIn();
final googleAuth = await googleUser!.authentication;
accessToken = googleAuth.accessToken;
idToken = googleAuth.idToken;
}
if (idToken == null) {
throw 'No ID Token';
}
if (accessToken == null) {
throw 'No Access Token';
throw 'No Access Token found.';
}
if (idToken == null) {
throw 'No ID Token found.';
}
return supabase.auth.signInWithIdToken(
provider: Provider.google,
idToken: idToken,
accessToken: accessToken,
nonce: rawNonce,
);
}
@@ -300,87 +235,10 @@ In terms of UI, this page is very simple, it just has a basic `Scaffold` with an
![Google sign in](/images/blog/flutter-authentication/google-sign-in.png)
Let’s break down what is going on within the `onPressed` callback of the sign in button.
At the top, we check on which platform the user is running the application.
We will break down the iOS flow, because it helps us understand how the Open ID Connect flow works.
First, we are generating a [nonce](https://openid.net/specs/openid-connect-core-1_0.html#SelfIssuedDiscovery:~:text=auth_time%20response%20parameter.)-,nonce,-String%20value%20used), which is essentially just a random string. This string is later passed to Google after being hashed to verify that the ID token has not been tampered to prevent a man-in-the-middle attack.
```dart
// Random string to verify the integrity of the ID Token
final rawNonce = _generateRandomString();
final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString();
```
`clientId` and `applicationId` are the app-specific values. These will be used to the authentication request to Google later on.
```dart
/// Client ID that you registered with Google Cloud.
/// You will have two different values for iOS and Android.
final clientId = Platform.isIOS ? 'IOS_CLIENT_ID' : 'ANDROID_CLIENT_ID';
```
`redirectUrl` is the URL at which the user will be redirected after a successful authentication request. For Google sign-in, we can set it to the reversed DNS form of the client ID followed by `:/`. `discoveryUrl` is a URL provided by Google that contains information about their Open ID configuration.
```dart
/// Set as reversed DNS form of Google Client ID + `:/` for Google login
final redirectUrl = '${clientId.split('.').reversed.join('.')}:/';
/// Fixed value for google login
const discoveryUrl = 'https://accounts.google.com/.well-known/openid-configuration';
```
Then we are sending an authorization request to Google. This is where the user is taken to Google’s page to perform sign in and consent our app to obtain some personal information. Note that we are requesting three scopes here. `openid` and `email` are required by Supabase auth to complete the sign-in process. `profile` is not required by Supabase auth, but we are requesting it to display some profile information on the profile screen later on. We do not actually obtain the requested information in this step though. All we are doing is requesting an access token that has permission to obtain the personal information we have requested.
```dart
// Authorize the user by opening the concent page
final result = await appAuth.authorize(
AuthorizationRequest(
clientId,
redirectUrl,
discoveryUrl: discoveryUrl,
nonce: hashedNonce,
scopes: [
'openid',
'email',
'profile',
],
),
);
```
Using the authorization token obtained in the previous step, we make the final request to Google’s auth server to obtain the personal information we asked for earlier. We get an ID token in return, which contains the personal information.
```dart
// Request the access and id token to google
final tokenResult = await appAuth.token(
TokenRequest(
clientId,
redirectUrl,
authorizationCode: result.authorizationCode,
discoveryUrl: discoveryUrl,
codeVerifier: result.codeVerifier,
nonce: result.nonce,
scopes: [
'openid',
'email',
'profile',
],
),
);
```
And lastly, we pass the ID token we obtained from Google to Supabase to complete the sign-in on Supabase auth. Once the user is signed in, the auth state listener in the `initState` fires and takes the user to the `ProfileScreen`.
```dart
await supabase.auth.signInWithIdToken(
provider: Provider.google,
idToken: idToken,
nonce: rawNonce,
);
```
The android flow goes through similar steps, but all of the heavy lifting of obtaining the access token and ID token is done by the `google_sign_in` package.
Within the `onPressed` callback of the button, we are calling the `_googleSignIn` method.
This method calls the Google sign-in package to perform the sign-in flow.
Once the user completes the sign-in flow, we obtain an access token and an ID token.
We will pass these tokens to Supabase auth to then obtain a Supabase session.
## Create the Profile Screen
Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

After

Width:  |  Height:  |  Size: 274 KiB

@@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
# This file should be version controlled and should not be manually edited.
version:
revision: 796c8ef79279f9c774545b3771238c3098dbefab
channel: stable
revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e"
channel: "stable"
project_type: app
@@ -13,26 +13,26 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: android
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: ios
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: linux
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: macos
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: web
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
- platform: windows
create_revision: 796c8ef79279f9c774545b3771238c3098dbefab
base_revision: 796c8ef79279f9c774545b3771238c3098dbefab
create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
# User provided section
@@ -52,10 +52,6 @@ android {
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
// You need an empty manifestPlaceholders for appauth to not throw an error
manifestPlaceholders += [
'appAuthRedirectScheme': ''
]
multiDexEnabled true
}
@@ -8,9 +8,17 @@ PODS:
- AppAuth/ExternalUserAgent (1.6.2):
- AppAuth/Core
- Flutter (1.0.0)
- flutter_appauth (0.0.1):
- AppAuth (= 1.6.2)
- google_sign_in_ios (0.0.1):
- Flutter
- GoogleSignIn (~> 6.2)
- GoogleSignIn (6.2.4):
- AppAuth (~> 1.5)
- GTMAppAuth (~> 1.3)
- GTMSessionFetcher/Core (< 3.0, >= 1.1)
- GTMAppAuth (1.3.1):
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 3.0, >= 1.5)
- GTMSessionFetcher/Core (2.3.0)
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
@@ -27,7 +35,7 @@ PODS:
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
- Flutter (from `Flutter`)
- flutter_appauth (from `.symlinks/plugins/flutter_appauth/ios`)
- google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
@@ -37,14 +45,17 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- AppAuth
- GoogleSignIn
- GTMAppAuth
- GTMSessionFetcher
EXTERNAL SOURCES:
app_links:
:path: ".symlinks/plugins/app_links/ios"
Flutter:
:path: Flutter
flutter_appauth:
:path: ".symlinks/plugins/flutter_appauth/ios"
google_sign_in_ios:
:path: ".symlinks/plugins/google_sign_in_ios/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
@@ -60,9 +71,12 @@ SPEC CHECKSUMS:
app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_appauth: cf9b928962105b2a64a9802585d1c8adaf3e0f46
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
google_sign_in_ios: 1256ff9d941db546373826966720b0c24804bcdd
GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a
GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd
GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
@@ -7,15 +7,15 @@
objects = {
/* Begin PBXBuildFile section */
139D526D6DAAC306FF934AF7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4AAD0E3ADC689337ACEF792 /* Pods_Runner.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3304FB9E97805348E2562BE0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B564902DECB04C26DF5C1990 /* Pods_Runner.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
DEA8302A70C9ACD2650F9B7C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 828A241E8FA8208665D3EB86 /* Pods_RunnerTests.framework */; };
BAB0D682C8D30413CA341239 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAAD19358373E12AFFCF4373 /* Pods_RunnerTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -42,19 +42,17 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
01D09B21062AD4556A06A6E3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
0CD475A43E8DA600E2B982AC /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
27BEFA69E5DA94D046EFBE00 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
20BC47085BC335E3D8D7FC90 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
38E30A4AF317B140613697D2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
426FE104D430BF3CD70AF9E2 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
472D51D7E326E44047EEC5F0 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
828A241E8FA8208665D3EB86 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -62,31 +60,56 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B564902DECB04C26DF5C1990 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D0870FF5D39BE2F0E613C78C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
F00CBB189671F834144DE713 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
B60B31F58DF0279BAF4DA310 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
C94B4E330EE1AD8F6C0AC8F7 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
DAAD19358373E12AFFCF4373 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E4AAD0E3ADC689337ACEF792 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FA53A77B0831C3F3DE80EA3D /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
71EF4399EB075B7C77CF3021 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BAB0D682C8D30413CA341239 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3304FB9E97805348E2562BE0 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F0B9F11E87752367F31C27C8 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DEA8302A70C9ACD2650F9B7C /* Pods_RunnerTests.framework in Frameworks */,
139D526D6DAAC306FF934AF7 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1DB24B391EB6593AFC13AA32 /* Pods */ = {
isa = PBXGroup;
children = (
20BC47085BC335E3D8D7FC90 /* Pods-Runner.debug.xcconfig */,
B60B31F58DF0279BAF4DA310 /* Pods-Runner.release.xcconfig */,
01D09B21062AD4556A06A6E3 /* Pods-Runner.profile.xcconfig */,
0CD475A43E8DA600E2B982AC /* Pods-RunnerTests.debug.xcconfig */,
C94B4E330EE1AD8F6C0AC8F7 /* Pods-RunnerTests.release.xcconfig */,
FA53A77B0831C3F3DE80EA3D /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
256B90543BCD7B7737B4F6B3 /* Frameworks */ = {
isa = PBXGroup;
children = (
E4AAD0E3ADC689337ACEF792 /* Pods_Runner.framework */,
DAAD19358373E12AFFCF4373 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
@@ -95,28 +118,6 @@
path = RunnerTests;
sourceTree = "<group>";
};
4147D33225043F42F09814E7 /* Pods */ = {
isa = PBXGroup;
children = (
D0870FF5D39BE2F0E613C78C /* Pods-Runner.debug.xcconfig */,
38E30A4AF317B140613697D2 /* Pods-Runner.release.xcconfig */,
F00CBB189671F834144DE713 /* Pods-Runner.profile.xcconfig */,
27BEFA69E5DA94D046EFBE00 /* Pods-RunnerTests.debug.xcconfig */,
472D51D7E326E44047EEC5F0 /* Pods-RunnerTests.release.xcconfig */,
426FE104D430BF3CD70AF9E2 /* Pods-RunnerTests.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
83C49BB5102259C76EED0D53 /* Frameworks */ = {
isa = PBXGroup;
children = (
B564902DECB04C26DF5C1990 /* Pods_Runner.framework */,
828A241E8FA8208665D3EB86 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -135,8 +136,8 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
4147D33225043F42F09814E7 /* Pods */,
83C49BB5102259C76EED0D53 /* Frameworks */,
1DB24B391EB6593AFC13AA32 /* Pods */,
256B90543BCD7B7737B4F6B3 /* Frameworks */,
);
sourceTree = "<group>";
};
@@ -171,10 +172,10 @@
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
42C78DCFB35050844813EE93 /* [CP] Check Pods Manifest.lock */,
3F6E40BE5EE61FB34D24E363 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
F0B9F11E87752367F31C27C8 /* Frameworks */,
71EF4399EB075B7C77CF3021 /* Frameworks */,
);
buildRules = (
);
@@ -190,14 +191,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
72352E8546CF6F5BA1AA1932 /* [CP] Check Pods Manifest.lock */,
D13F0F6643ACD43F91A0DCB3 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
D5C0C78971716833C4CC4F79 /* [CP] Embed Pods Frameworks */,
2B4EFE470EC5A13A344C8224 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -214,7 +215,8 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
@@ -268,6 +270,23 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
2B4EFE470EC5A13A344C8224 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -284,7 +303,7 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
42C78DCFB35050844813EE93 /* [CP] Check Pods Manifest.lock */ = {
3F6E40BE5EE61FB34D24E363 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -306,7 +325,22 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
72352E8546CF6F5BA1AA1932 /* [CP] Check Pods Manifest.lock */ = {
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
D13F0F6643ACD43F91A0DCB3 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -328,38 +362,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
D5C0C78971716833C4CC4F79 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -484,14 +486,14 @@
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 27BEFA69E5DA94D046EFBE00 /* Pods-RunnerTests.debug.xcconfig */;
baseConfigurationReference = 0CD475A43E8DA600E2B982AC /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.myAuthApp.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.example.myauthapp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -502,14 +504,14 @@
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 472D51D7E326E44047EEC5F0 /* Pods-RunnerTests.release.xcconfig */;
baseConfigurationReference = C94B4E330EE1AD8F6C0AC8F7 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.myAuthApp.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.example.myauthapp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -518,14 +520,14 @@
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 426FE104D430BF3CD70AF9E2 /* Pods-RunnerTests.profile.xcconfig */;
baseConfigurationReference = FA53A77B0831C3F3DE80EA3D /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.myAuthApp.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.example.myauthapp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -2,12 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>My Auth App</string>
<string>Myauthapp</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -15,7 +13,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Supabase Auth</string>
<string>myauthapp</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@@ -26,8 +24,6 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
@@ -45,7 +41,22 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<!-- TODO Replace this value: -->
<!-- Copied from GoogleService-Info.plist key REVERSED_CLIENT_ID -->
<string>com.googleusercontent.apps.my-ios</string>
</array>
</dict>
</array>
</dict>
</plist>
@@ -1,10 +1,4 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:flutter_appauth/flutter_appauth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:myauthapp/main.dart';
import 'package:myauthapp/screens/profile_screen.dart';
@@ -37,103 +31,40 @@ class _LoginScreenState extends State<LoginScreen> {
});
}
/// Function to generate a random 16 character string.
String _generateRandomString() {
final random = Random.secure();
return base64Url.encode(List<int>.generate(16, (_) => random.nextInt(256)));
}
Future<AuthResponse> _googleSignIn() async {
/// TODO: update the iOS and Web client ID with your own.
/// TODO: update the Web client ID with your own.
///
/// Client ID that you registered with Google Cloud.
/// Note that in order to perform Google sign in on Android, you need to
/// provide the web client ID, not the Android client ID.
final clientId = Platform.isIOS ? 'IOS_CLIENT_ID' : 'WEB_CLIENT_ID';
/// Web Client ID that you registered with Google Cloud.
const webClientId = 'my-web.apps.googleusercontent.com';
late final String? idToken;
late final String? accessToken;
String? rawNonce;
/// TODO: update the iOS client ID with your own.
///
/// iOS Client ID that you registered with Google Cloud.
const iosClientId = 'my-ios.apps.googleusercontent.com';
// Use AppAuth to perform Google sign in on iOS
// and use GoogleSignIn package for Google sign in on Android
if (Platform.isIOS) {
const appAuth = FlutterAppAuth();
// Google sign in on Android will work without providing the Android
// Client ID registered on Google Cloud.
// Just a random string
rawNonce = _generateRandomString();
final hashedNonce = sha256.convert(utf8.encode(rawNonce)).toString();
final GoogleSignIn googleSignIn = GoogleSignIn(
clientId: iosClientId,
serverClientId: webClientId,
);
final googleUser = await googleSignIn.signIn();
final googleAuth = await googleUser!.authentication;
final accessToken = googleAuth.accessToken;
final idToken = googleAuth.idToken;
/// Set as reversed DNS form of Google Client ID + `:/` for Google login
final redirectUrl = '${clientId.split('.').reversed.join('.')}:/';
/// Fixed value for google login
const discoveryUrl =
'https://accounts.google.com/.well-known/openid-configuration';
// authorize the user by opening the concent page
final result = await appAuth.authorize(
AuthorizationRequest(
clientId,
redirectUrl,
discoveryUrl: discoveryUrl,
nonce: hashedNonce,
scopes: [
'openid',
'email',
'profile',
],
),
);
if (result == null) {
throw 'No result';
}
// Request the access and id token to google
final tokenResult = await appAuth.token(
TokenRequest(
clientId,
redirectUrl,
authorizationCode: result.authorizationCode,
discoveryUrl: discoveryUrl,
codeVerifier: result.codeVerifier,
nonce: result.nonce,
scopes: [
'openid',
'email',
],
),
);
accessToken = tokenResult?.accessToken;
idToken = tokenResult?.idToken;
} else {
final GoogleSignIn googleSignIn = GoogleSignIn(
serverClientId: clientId,
scopes: [
'openid',
'email',
],
);
final googleUser = await googleSignIn.signIn();
final googleAuth = await googleUser!.authentication;
accessToken = googleAuth.accessToken;
idToken = googleAuth.idToken;
}
if (idToken == null) {
throw 'No ID Token';
}
if (accessToken == null) {
throw 'No Access Token';
throw 'No Access Token found.';
}
if (idToken == null) {
throw 'No ID Token found.';
}
return supabase.auth.signInWithIdToken(
provider: Provider.google,
idToken: idToken,
accessToken: accessToken,
nonce: rawNonce,
);
}
@@ -82,7 +82,7 @@ packages:
source: hosted
version: "3.1.1"
crypto:
dependency: "direct main"
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
@@ -118,22 +118,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_appauth:
dependency: "direct main"
description:
name: flutter_appauth
sha256: "19031ea2438a513762e64ec7b58ae1f00cad6fb87f818e405325cd183dfb9fec"
url: "https://pub.dev"
source: hosted
version: "6.0.2"
flutter_appauth_platform_interface:
dependency: transitive
description:
name: flutter_appauth_platform_interface
sha256: "44feaa7058191b5d3cd7c9ff195262725773643121bcada172d49c2ddcff71cb"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_lints:
dependency: "direct dev"
description:
@@ -13,8 +13,6 @@ dependencies:
sdk: flutter
supabase_flutter: ^1.10.19
flutter_appauth: ^6.0.0
crypto: ^3.0.3
google_sign_in: ^6.1.5
dev_dependencies: