This guide is a walkthrough on how to integrate Frontegg’s authentication magic into your app using the Frontegg Flutter SDK. Whether you need to add secure sign-ups, logins, multi-factor authentication, or even social logins, this guide has you covered with simple, step-by-step instructions to get things rolling in no time.
Prerequisites
Prerequisites
Frontegg Hosted Login is required, and setting a custom domain is highly recommended.
iOS ≥ 14
Android ≥ 26
Navigate to Frontegg Portal Settings, If you don't have application
follow the integration steps after signing up. Copy FronteggDomain to future steps from Frontegg Portal Domain

- Navigate to Login Method Settings
- Toggle on Hosted login method for iOS:
- Add
{{IOS_BUNDLE_IDENTIFIER}}://{{FRONTEGG_BASE_URL}}/ios/oauth/callback
- Add
- Toggle Hosted login method for Android:
- Add
{{ANDROID_PACKAGE_NAME}}://{{FRONTEGG_BASE_URL}}/android/oauth/callback - Add
https://{{FRONTEGG_BASE_URL}}/oauth/account/redirect/android/{{ANDROID_PACKAGE_NAME}}
- Add
- Replace
IOS_BUNDLE_IDENTIFIERwith your application identifier - Replace
FRONTEGG_BASE_URLwith your Frontegg base url, without https, i.eFronteggDomain. - Replace
ANDROID_PACKAGE_NAMEwith your android package name
dart pub add frontegg_flutterOr manually:
dependencies:
frontegg_flutter: ^1.0.0To setup your SwiftUI application to communicate with Frontegg, you have to create a new file named Frontegg.plist
under your root project directory, this file will store values to be used variables by Frontegg SDK:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>baseUrl</key>
<string>https://[DOMAIN_HOST_FROM_PREVIOUS_STEP]</string>
<key>clientId</key>
<string>[CLIENT_ID_FROM_PREVIOUS_STEP]</string>
</dict>
</plist>Prerequisites
Prerequisites
The use of this feature requires @frontegg/flutter@1.0.1
This guide outlines the steps to configure your iOS application to support multiple applications.
Modify the Frontegg.plist file and add applicationId to Frontegg.plist file:
<plist version="1.0">
<dict>
<key>applicationId</key>
<string>your-application-id-uuid</string>
<key>baseUrl</key>
<string>https://your-domain.fronteg.com</string>
<key>clientId</key>
<string>your-client-id-uuid</string>
</dict>
</plist>To handle Login with magic link and other authentication methods that require to open the app with a URL, you have to add the following code to.
- Create
FronteggSwiftAdapter.swiftin your project and add the following code:
// FronteggSwiftAdapter.swift
import Foundation
import FronteggSwift
@objc(FronteggSwiftAdapter)
public class FronteggSwiftAdapter: NSObject {
@objc public static let shared = FronteggSwiftAdapter()
@objc public func handleOpenUrl(_ url: URL) -> Bool {
return FronteggAuth.shared.handleOpenUrl(url)
}
}- Open
AppDelegate.mfile and import swift headers:
#import <[YOUR_PROJECT_NAME]-Swift.h>- Add URL handlers to
AppDelegate.m:
#import <[YOUR_PROJECT_NAME]-Swift.h>
// ...CODE...
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
if([[FronteggSwiftAdapter shared] handleOpenUrl:url] ){
return TRUE;
}
return [RCTLinkingManager application:app openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
if (userActivity.webpageURL != NULL){
if([[FronteggSwiftAdapter shared] handleOpenUrl:userActivity.webpageURL] ){
return TRUE;
}
}
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}- Open
AppDelegate.mfile and import swift headers:
import FronteggSwift- Add URL handlers to
AppDelegate.swift:
import UIKit
import FronteggSwift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
/*
* Called when the app was launched with a url. Feel free to add additional processing here,
* but if you want the App API to support tracking app url opens, make sure to keep this call
*/
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
if(FronteggAuth.shared.handleOpenUrl(url, true)){
return true
}
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
/*
* Called when the app was launched with an activity, including Universal Links.
* Feel free to add additional processing here, but if you want the App API to support
* tracking app url opens, make sure to keep this call
*/
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let url = userActivity.webpageURL {
if(FronteggAuth.shared.handleOpenUrl(url, true)){
return true
}
}
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
}Configuring your iOS associated domain is required for Magic Link authentication / Reset Password / Activate Account.
- In order to add your iOS associated domain to your Frontegg application, you will need to update in each of your
integrated Frontegg Environments the iOS associated domain that you would like to use with that Environment. Send a POST request tohttps://api.frontegg.com/vendors/resources/associated-domains/v1/ioswith the following payload:
{
"appId":[YOUR_ASSOCIATED_DOMAIN]
}In order to use our API’s, follow this guide to generate a vendor token.
Next, you will need to add your associated domain to your iOS application. To do so, follow the steps below:
- Open your project in Xcode.
- Select your project in the Project Navigator.
- Select your target.
- Select the Signing & Capabilities tab.
- Expand the Associated Domains section.
- Click the + button.
- Enter your associated domain in the format
applinks:[YOUR_ASSOCIATED_DOMAIN]. - Enter your associated domain in the format
webcredentials:[YOUR_ASSOCIATED_DOMAIN]. - Click Done.
[YOUR_ASSOCIATED_DOMAIN] is the associated domain that you would like to use with your iOS application.
For example, if you would like to use https://example.com as your associated domain, you would enter applinks:example.com and webcredentials:example.com.
To set up your Android minimum sdk version, open root gradle file atandroid/build.gradle, and add/edit the minSdkVersion under buildscript.ext:
buildscript {
ext {
minSdkVersion = 26
// ...
}
}To set up your Android application on to communicate with Frontegg, you have to add buildConfigField property the
gradle android/app/build.gradle. This property will store frontegg hostname (without https) and client id from previous step:
def fronteggDomain = "FRONTEGG_DOMAIN_HOST.com" // without protocol https://
def fronteggClientId = "FRONTEGG_CLIENT_ID"
android {
defaultConfig {
manifestPlaceholders = [
"package_name" : applicationId,
"frontegg_domain" : fronteggDomain,
"frontegg_client_id": fronteggClientId
]
buildConfigField "String", 'FRONTEGG_DOMAIN', "\"$fronteggDomain\""
buildConfigField "String", 'FRONTEGG_CLIENT_ID', "\"$fronteggClientId\""
buildConfigField "Boolean", 'FRONTEGG_USE_ASSETS_LINKS', "true" /** For using frontegg domain for deeplinks **/
buildConfigField "Boolean", 'FRONTEGG_USE_CHROME_CUSTOM_TABS', "true" /** For using custom chrome tab for social-logins **/
}
}NOTE:
FRONTEGG_USE_ASSETS_LINKS by default is true.FRONTEGG_USE_CHROME_CUSTOM_TABS by default is true.
So, if you do not set up those values we will use the default ones.
Add bundleConfig=true if it does not exist inside the android section inside the app gradle android/app/build.gradle
android {
buildFeatures {
buildConfig = true
}
}Add INTERNET permission to the app's manifest file.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>Configuring your Android AssetLinks is required for Magic Link authentication / Reset Password / Activate Account /
login with IdPs.
To add your AssetLinks to your Frontegg application, you will need to update in each of your integrated Frontegg
Environments the AssetLinks that you would like to use with that Environment. Send a POST request to https://api.frontegg.com/vendors/resources/associated-domains/v1/android with the following payload:
{
"packageName": "YOUR_APPLICATION_PACKAGE_NAME",
"sha256CertFingerprints": ["YOUR_KEYSTORE_CERT_FINGERPRINTS"]
}Each Android app has multiple certificate fingerprint, to get your DEBUG sha256CertFingerprint you have to run the
below command. For Debug mode, run the following command and copy the SHA-256 value.
NOTE: make sure to choose the Variant and Config equals to debug
./gradlew signingReport
###################
# Example Output:
###################
# Variant: debug
# Config: debug
# Store: /Users/davidfrontegg/.android/debug.keystore
# Alias: AndroidDebugKey
# MD5: 25:F5:99:23:FC:12:CA:10:8C:43:F4:02:7D:AD:DC:B6
# SHA1: FC:3C:88:D6:BF:4E:62:2E:F0:24:1D:DB:D7:15:36:D6:3E:14:84:50
# SHA-256: D9:6B:4A:FD:62:45:81:65:98:4D:5C:8C:A0:68:7B:7B:A5:31:BD:2B:9B:48:D9:CF:20:AE:56:FD:90:C1:C5:EE
# Valid until: Tuesday, 18 June 2052For Release mode, Extract the SHA256 using keytool from your Release keystore file:
keytool -list -v -keystore /PATH/file.jks -alias YourAlias -storepass *** -keypass ***To enable social login using Chrome Custom Tabs within your Android application, you need to modify the android/app/build.gradle file. Add a boolean buildConfigField for the FRONTEGG_USE_CHROME_CUSTOM_TABS flag and set it to true. By default, the SDK defaults to using the Chrome browser for social login.
def fronteggDomain = "FRONTEGG_DOMAIN_HOST.com" // without protocol https://
def fronteggClientId = "FRONTEGG_CLIENT_ID"
android {
defaultConfig {
manifestPlaceholders = [
"package_name" : applicationId,
"frontegg_domain" : fronteggDomain,
"frontegg_client_id": fronteggClientId
]
buildConfigField "String", 'FRONTEGG_DOMAIN', "\"$fronteggDomain\""
buildConfigField "String", 'FRONTEGG_CLIENT_ID', "\"$fronteggClientId\""
buildConfigField "Boolean", 'FRONTEGG_USE_CHROME_CUSTOM_TABS', "true"
}
}Prerequisites
Prerequisites
The use of this feature requires minimum @frontegg/flutter@1.0.1
Modify the Build.gradle file and add FRONTEGG_APPLICATION_ID buildConfigField into the build.gradle file:
def fronteggApplicationId = "your-application-id-uuid"
...
android {
...
buildConfigField "String", 'FRONTEGG_APPLICATION_ID', "\"$fronteggApplicationId\""
}import 'package:flutter/material.dart';
import 'package:frontegg_flutter/frontegg_flutter.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FronteggProvider(
child: const MainPage(),
),
);
}
}Or use Provider from the plugin or other suitable plugin. Make sure to dispose of the FronteggFlutter:
import 'package:flutter/material.dart';
import 'package:frontegg_flutter/frontegg_flutter.dart';
import 'package:provider/provider.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Provider(
create: (_) => FronteggFlutter(),
dispose: (_, frontegg) => frontegg.dispose(),
child: const MainPage(),
),
);
}
}To get the FronteggFlutter instance use the Frontegg BuildContext extension down the widget tree:
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
final frontegg = context.frontegg;
return const SizedBox();
}
}To login with Frontegg you can use the context.frontegg accessor and call login method:
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
final frontegg = context.frontegg;
return Scaffold(
body: Center(
child: ElevatedButton(
child: const Text("Login"),
onPressed: () async {
await frontegg.login();
},
),
),
);
}
}To switch a user's tenant you can use the context.frontegg accessor and call switchTenant method:
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
final frontegg = context.frontegg;
return Scaffold(
body: Center(
child: ElevatedButton(
child: const Text("Login"),
onPressed: () async {
final tenantId = "TENANT_ID";
await frontegg.switchTenant(tenantId);
},
),
),
);
}
}FronteggPlugin has a FronteggState and this state is changing according to the plugin flowing:
class FronteggState {
final String? accessToken;
final String? refreshToken;
final FronteggUser? user;
final bool isAuthenticated;
final bool isLoading;
final bool initializing;
final bool showLoader;
final bool appLink;
}To get the state of the FronteggFlutter you have two options:
- Get
currentState:
@override
Widget build(BuildContext context) {
final frontegg = context.frontegg;
final fronteggState = frontegg.currentState;
}- Listen to
stateChangedstream:
import 'package:flutter/material.dart';
import 'package:frontegg_flutter/frontegg_flutter.dart';
import 'package:frontegg_flutter_example/login_page.dart';
import 'package:frontegg_flutter_example/user_page.dart';
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
final frontegg = context.frontegg;
return Scaffold(
body: Center(
child: StreamBuilder<FronteggState>(
stream: frontegg.stateChanged,
builder: (BuildContext context, AsyncSnapshot<FronteggState> snapshot) {
if (snapshot.hasData) {
final state = snapshot.data!;
if (state.isAuthenticated && state.user != null) {
return const UserPage();
} else if (state.initializing) {
return const CircularProgressIndicator();
} else {
return const LoginPage();
}
}
return const SizedBox();
},
),
),
);
}
}logout- logs out fromFronteggFlutter;refreshToken- refreshesaccessTokenandrefreshTokenonly if needed, returnstrueif refreshing succeeds;getConstants- returnsFrontegg Flutterinitialization constants;directLoginAction- direct login withtypeanddata.