We've created a cross-platform Flutter application that effortlessly integrates sign-in options through Google, Apple, and Magic Link authentication. As a result, users can access their favorite features from any device, knowing that the sign-in process remains consistent across all platforms.
In this article, you will discover why Supabase became our choice and how we used Supabase Auth to enable sign-in via three major providers. We will also describe the obstacles we faced along the way. Intrigued? Keep reading.
One of the common business requirements when starting a new app development is implementing social and email sign-in. Finding a reliable authentication provider, especially in the ever-evolving app development landscape, is quite difficult. If you want to learn what lies beneath the whole concept, check out our article about Identity Management.
Several Identity Management Solutions are available on the market. One of the common choices is Firebase Authentication by Google, which is well known for being quite easy to implement Google sign-in due to the shared Google ecosystem. However, there is one noteworthy contender in the Flutter authentication arena that deserves attention.
Supabase advertises itself as “an open-source alternative to Firebase.” It not only offers a wide array of third-party authentication methods but also officially provides Dart and Flutter packages in the pub.dev package repository, which significantly accelerates Flutter app development.
At LeanCode, we started a demanding Flutter project that required the creation of a single Flutter app for a remarkable number of six platforms (including three desktop platforms):
One business requirement was to enable users to log in the same way on each of the 6 platforms. This project was implemented by a team consisting entirely of mobile application developers, and the requirement for a cross-platform application pushed us to seek a reliable SaaS authentication provider.
Now, let's dive into Supabase features.
Supabase Auth, also known as open source Firebase alternative, caught the attention of our development team first and foremost because it supports all three integrations: Apple auth, Google auth, and Magic Link sign-in. Apart from authentication, Supabase offers other useful tools that allow adding advanced functionalities to the app.
The first and most significant one is the SQL database accessible from the mobile platform, with row-level security included for every project. From a web browser, developers can access a table editor, easily view data by writing SQL queries, and control which users are permitted to perform operations on rows within tables and views. Since the database and authentication come from a single provider, it simplifies integration and eases implementation. This fact made Supabase a strong candidate when choosing an auth provider in our projects’ initial phase.
Supabase also offers real-time messages out of the box, enabling devices to listen to Postgres database changes and send messages to authorized clients. This is a good foundation for implementing instant data synchronization across user devices, which we facilitated in the later phase of the project.
The next helpful feature from Supabase is Edge Functions. These are server-side TypeScript functions distributed globally at the edge, near the users. Functions can be called directly from inside your Flutter app and enable complex operations on multiple tables, which typically would require admin access to the database. Functions are useful when implementing, for example, user account deletion because this operation requires removing user data from the profiles table, a user from the user registry, and all corresponding user data from tables.
Apart from the features above, Supabase provides comprehensive documentation that includes step-by-step instructions on configuring authentication for each provider, not only in Flutter but in any programming language for which Supabase provides libraries. The documentation contains Flutter examples and Dart snippets, making it easier for developers to familiarize themselves with the setup process.
Knowing Supabase advantages, let’s explore the authentication flows.
It’s time to explain sign-in with Google, Apple, and a Magic Link authentication flows. In this paragraph, you will also learn what a native sign-in is and how it makes the authentication process more pleasant for users.
Starting with Google sign-in, Supabase requires the setup of a new project in the Google Cloud Platform (GCP) and obtaining OAuth 2 credentials. In the app authentication flow looks as follows:
Moving on to Apple sign-In, it also requires configuring the Apple provider credentials in the Supabase dashboard. The flow is very similar to Google sign-in:
When it comes to logging in with Apple, it’s important that users can still use their Apple ID to log in on devices outside of the Apple ecosystem by using a web browser.
The Magic Link authentication method it’s a password-less sign-in approach, where a user just submits an email address. There is no distinction between sign-in and sign-up in the app - the user fills in only one form field. After form submission, Supabase internally decides if the user should receive a “Confirm Signup” or “Sign-in with Magic Link” email. In the Supabase console, two separate Email templates can be configured, each containing the appropriate information, and the user receives an appropriate one depending on whether the account exists or not. The process is simple as follows:
There’s also a native sign-in for Apple and Google, apart from previously mentioned flows. It allows users to log into the app by using familiar-looking dialogs similar to those on the devices they use, such as Android and iOS. Before the native sign-in introduction in August 2023, users needed to sign-in by using the default device’s web browser and type in their login and password from the beginning. Native sign-in removes this extra step in the process and keeps it entirely within the app. There is no need to open a web browser, which makes user login quicker and overall experience more friendly. Documentation describes the underlying architecture as follows:
”Behind the scenes, these native sign-in methods use ID tokens. They’re a formalised version of a JWT that is issued by Apple or Google and contain profile information. Supabase Auth now can properly validate the ID tokens and create new or link to existing user accounts based on email similarity (…) OS and Android, offer a built-in identity provider for convenient user authentication.”
Developers, on the other hand, can implement native sign-in easily by using packages sign_in_with_apple, google_sign_in, and supabase_flutter. They all contain a handful of authentication methods that can be easily used directly in Flutter code. Native is available on iOS, macOS, tvOS and watchOS apps in the Apple ecosystem and all Android variants in the Google ecosystem. What is important sign-in via a web browser remains still available outside these platforms.
Redirecting the user back to the app after sign-in is the penultimate step in the sign-in process. Making sure that the user will be properly brought back to the app on whichever platform the app runs is important, especially since specific platforms require different URLs.
In the app, developers can specify the URL to which the app should redirect users after a successful sign-in. In the Supabase console, only one default redirect URL can be set, which will be used if no redirect URL is specified in the app. Other URLs, besides the default one, can be used in Flutter code, but they need to be whitelisted — added to the allow list in the console.
We leveraged this flexibility and utilised the flutter/foundation package to detect the platform the app is running on. To achieve this, we've created an enum AppPlatform with a String getter signInRedirectUrl, which returns a redirect URL suited to the platform the app is running on. Within this enum we added 2 constant redirect URLs: webUrl and deeplinkUrl, returned depending on the boolean isWeb. Check the implementation on the following example:
enum AppPlatform {
String get signInRedirectUrl {
const webUrl = 'https://${web_app_url}/login-callback/';
const deeplinkUrl = '${deeplink_url_scheme}://login-callback/';
return isWeb ? webUrl : deeplinkUrl;
}
Continuing with proper URL usage, the supabase_client library contains two methods: signInWithOAuth and signInWithOtp. Both allow setting redirectTo parameter and do exactly what we need - properly redirect back to the app after successful sign-in.
class SignInCubit {
Future<void> signInWithSocialAuth(SocialLogin social) async {
// Sign in via Google/Apple auth provider
SupabaseClient.auth.signInWithOAuth(
social.provider, // Provider.google or Provider.apple
redirectTo: AppPlatform.current.signInRedirectUrl,
authScreenLaunchMode: LaunchMode.externalApplication,
);
}
Future<void> signInWithOTP({required String email}){
// Sign in using magic-link
SupabaseClient.auth.signInWithOtp(
email: email,
emailRedirectTo: AppPlatform.current.signInRedirectUrl,
);
}
}
Please note that for app state management, we use Cubits from the flutter_bloc package. If you want to learn how to use Bloc and Cubit, please check the readme and example in the package documentation.
💡 Important facts: When signing in via magic-link/one-time password, the user can open an email on any device. However, one Magic Link can be used only once. For example, a user can’t use the same email to first sign-in on mobile, and then sign-in on the web using the link from the same email. The web browser will first attempt to open the native app or inform the user that the app is not installed.
Implementing sign-in on Linux was quite a journey. When building and distributing the Flutter app for Linux, you have many options.
We started by exploring the following three: AppImage, Snapcraft, and Flatpak. All of them represent a way of encapsulating an app into a package whose format is respected by various Linux distributions and enables successful app installation and running.
At first, we tried an approach of building the Flutter app into an AppImage. Unfortunately, when it came to redirecting back to the app after sign-in, we encountered an obstacle in the AppImage runtime. A redirect URL after sign-in is set to:
"{scheme-URL}//login-callback/" + URL fragment. The fragment contains long strings such as access_token, provider_token, token_type, and parameters expires_at & expires_in, making it quite a long URL.
It appeared that AppImage has an unpleasant buffer size limit of 1024 characters. Unfortunately, this limitation made it impossible to navigate back after signing in to the AppImage app. This bug, let’s say, can be fixed either by manually changing the AppImage builder and workflow or by waiting for a GitHub issue to be resolved. We did not want to change the AppImage builder manually and cared about time, so we were forced to seek an alternative solution for developing the application for Linux.
The next choice was Flatpak Builder, which eventually allowed us to distribute an app for Linux, but it also needed some tweaks. After finding the flutter_flatpak_example repo on GitHub, it became clear that building a Flutter app as a Flatpak is possible. The main changes we performed were adjusting the GitHub workflow to our project file structure and setting the app version and release date in the distributed Flatpak app. When it comes to redirecting back to the app after sign-in, the Linux app uses the same redirect URL as desktop and mobile versions of the app.
All this effort paid off, allowing us to build and distribute the Linux application successfully. Users can log in using Google, Apple, and the Magic Link.
We've successfully created a cross-platform Flutter app that supports sign-in via Google, Apple, and Magic Link authentication. Each sign-in method is supported on every one of the six platforms, increasing the convenience of using the app and making the sign-in experience similar on every device.
Choosing the right authentication provider is crucial to shortening the app's time to market. After using Supabase Auth in the current project, we can say it was a good choice. Its extensive range of authentication providers and good Flutter packages make development more pleasant, and a user-friendly web console makes user management much easier.
However, using Supabase is an example of how to create a new cross-platform app with an authentication feature. To learn about the Ory Kratos Identity Management Solution used in other LeanCode projects, please refer to the article series dedicated to this topic.
If you are looking for a custom software development service that includes a solution like this, you can order a free 30-minute consultation call with our experts.