iOS Swift SDK

Frontegg and iOS Swift

Frontegg's Mobile SDKs are officially here for you to explore and utilize. Our powerful and simple-to-implements SDKs are designed to empower you to create extraordinary mobile experiences. Whether you're developing for iOS, Android, React Native, or Ionic, we've got you covered.

Get ready to jump into the app development world with Swift and Frontegg. The following guide will walk you through integrating Frontegg's capabilities into iOS applications.

Table of Contents

Project Requirements

Supported Languages

Swift: The minimum supported Swift version is now 5.3.

Supported Platforms

Major platform versions are supported, starting from:

  • iOS > 14

Getting Started

Prepare Frontegg Workspace

Navigate to your Frontegg Portal Settings; if you don't have the application
follow the integration steps after signing up.
Copy FronteggDomain to future steps from Frontegg Portal Domain

Setup Hosted Login

  • Navigate to your Login Method Settings
  • Toggle on your Hosted login method.
  • Add {{IOS_BUNDLE_IDENTIFIER}}://{{FRONTEGG_BASE_URL}}/ios/oauth/callback.
  • Replace IOS_BUNDLE_IDENTIFIER with your application identifier.
  • Replace FRONTEGG_BASE_URL with your frontegg base url.

Add frontegg package to the project

  • Open your project.
  • Choose File -> Add Packages.
  • Enter https://github.com/frontegg/frontegg-ios-swift in your search field.
  • Press Add Package.

Create a Frontegg plist file

To setup your SwiftUI application for communication with Frontegg, you need to create a new file with the name Frontegg.plist under your root project's directory. This file will store values to be used as variables by Frontegg's SDK:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN">
<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>

SwiftUI integration

  • Add Frontegg Wrapper

    • To use Frontegg's SDK. wrap your Application Scene with FronteggWrapper, like so:

      
      import SwiftUI
      import FronteggSwift
      
      @main
      struct demoApp: App {
          var body: some Scene {
              WindowGroup {
                  FronteggWrapper {
                      MyApp()
                  }
              }
          }
      }
      
    • Modify the MyApp.swift file to render content if a user is authenticated:

      1. Add the @EnvironmentObject var fronteggAuth: FronteggAuth as shown below.
      2. Render your entire application based on thefronteggAuth.isAuthenticated
      struct MyApp: View {
        @EnvironmentObject var fronteggAuth: FronteggAuth
        
        var body: some View {
          ZStack {
            if fronteggAuth.isAuthenticated {
              [YOU APPLICATION TABS / ROUTER / VIEWS]
            } else  {
              
              Button {
                  fronteggAuth.login()
              } label: {
                  Text("Login Button")
              }
            }
          }
        }
      }
      
    • Add a Custom Loading Screen

    To use your own LoadingView / SplashScreen, do as follows:

    • Build your loading view in a separated file.
    • Pass LoadingView as AnyView to the FronteggWrapper
      FronteggWrapper(loaderView: AnyView(LoaderView())) {
        MyApp()
      }
      

UIKit integration

  • Add Frontegg UIKit Wrapper

    • Add Frontegg to the AppDelegate file

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
      
            FronteggApp.shared.didFinishLaunchingWithOptions()
          
            return true
        }
      
    • Create FronteggController class that extends AbstractFronteggController from FronteggSwift

        //
        //  FronteggController.swift
        //
        
        import UIKit
        import FronteggSwift
        
        class FronteggController: AbstractFronteggController {
        
            override func navigateToAuthenticated(){
                // This function will be called when the user is authenticated
                // to navigate your application to the authenticated screen
                
                let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
                let viewController = mainStoryboard.instantiateViewController(withIdentifier: "authenticatedScreen")
                self.view.window?.rootViewController = viewController
                self.view.window?.makeKeyAndVisible()
            }
        
        }
      
    • Create a new ViewController and set your FronteggController as a custom class (the custom class created in the previous step):
      ViewController custom class

    • Mark FronteggController as Storyboard Entry Point
      ViewController entry point

    • Setup SceneDelegate for Frontegg universal links:

        func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
            if let url = URLContexts.first?.url,
                url.startAccessingSecurityScopedResource() {
                defer  {
                    url.stopAccessingSecurityScopedResource()
                }
                if url.absoluteString.hasPrefix( FronteggApp.shared.baseUrl ) {
                    if(FronteggApp.shared.auth.handleOpenUrl(url)){
                        // Display your own Authentication View Controller
                        // to handle after oauth callback
                        window?.rootViewController = AuthenticationController()
                        window?.makeKeyAndVisible()
                        return
                    }
                }
                
            }
        }
        func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
            if let url = userActivity.webpageURL {
                if(FronteggApp.shared.auth.handleOpenUrl(url)){
                    // Display your own Authentication View Controller
                    // to handle after oauth callback
                    window?.rootViewController = AuthenticationController()
                    window?.makeKeyAndVisible()
                    return
                }
            }
        }
      
    • Access authenticated user by FronteggApp.shared.auth

          
        //
        //  ExampleViewController.swift
        //
        
        import UIKit
        import SwiftUI
        import FronteggSwift
        import Combine
        
        
        class ExampleViewController: UIViewController {
        
            // Label to display logged in user's email
            @IBOutlet weak var label: UILabel!
            var showLoader: Boolean = true
            
            override func viewDidLoad() {
                super.viewDidLoad()
                // Do any additional setup after loading the view.
                
                // subscribe to isAuthenticated and navigate to login page
                // if the user is not authenticated
      
                let fronteggAuth = FronteggApp.shared.auth
                let sub = AnySubscriber<Bool, Never>(
                    receiveSubscription: {query in
                        query.request(.unlimited)
                    }, receiveValue: { showLoader in
                       self.showLoader = showLoader
                       self.label.text = fronteggAuth.user?.email ?? "Unknown"
                       
                       if(!showLoader && !fronteggAuth.isAuthenticated){
                           // Display your own Authentication View Controller
                           // to handle after oauth callback
                           window?.rootViewController = AuthenticationController()
                           window?.makeKeyAndVisible()
                           return .none
                       }
                       return .unlimited
                    })
      
                FronteggApp.shared.auth.$showLoader.subscribe(sub)
                
            }
             
            @IBAction func logoutButton (){
                FronteggApp.shared.auth.logout()
            }
      
        }
        
      

Embedded Webview vs ASWebAuthenticationSession

Frontegg SDK supports two authentication methods:

  • Embedded Webview
  • ASWebAuthenticationSession

By default, Frontegg SDK will use Embedded Webview. to use ASWebAuthenticationSession you will need to set the embeddedMode to NO in your Frontegg.plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN">
<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>

        <!-- START -->
        <key>embeddedMode</key>
        <true/>
        <!-- END -->
    </dict>
</plist>

Configuring an iOS-associated Domain

Configuring your iOS-associated domain is required for Magic Link Authentication / Reset Password / Activate Account.

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 for that Environment. Send a POST request to https://api.frontegg.com/vendors/resources/associated-domains/v1/ios with the following payload:

{
    “appId”:[YOUR_ASSOCIATED_DOMAIN]
}

To use our API’s, follow this guide and generate a Vendor Token.

Next, you must add your associated domain to your iOS application. To do so, follow the steps below:

  1. Open your project in Xcode.
  2. Select your project in the Project Navigator.
  3. Select your target.
  4. Select the Signing & Capabilities tab.
  5. Expand the Associated Domains section.
  6. Click the + button.
  7. Enter your associated domain in the following format applinks:[YOUR_ASSOCIATED_DOMAIN].
  8. Enter your associated domain in the following format webcredentials:[YOUR_ASSOCIATED_DOMAIN].
  9. Press Done.

[YOUR_ASSOCIATED_DOMAIN] is the associated domain you want 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.

Multi-Region Support

This guide outlines how to configure your iOS application to support multiple regions.

Step 1: Modify the Frontegg.plist File

First, adjust your Frontegg.plist file to handle multiple regions:

Modifications:

  • Remove the existing baseUrl and clientId keys.
  • Add a new array key named regions. This array will hold dictionaries for each region.

Example Frontegg.plist Structure:

<key>regions</key>
<array>
  <dict>
    <key>key</key>
    <string>us-region</string>
    <key>baseUrl</key>
    <string>https://us-region-api.frontegg.com</string>
    <key>clientId</key>
    <string>your-client-id-for-us-region</string>
  </dict>
  <!-- Add additional regions in a similar format -->
</array>

Step 2: Add Associated Domains for Each Region

For each region, configure the associated domains in your application's settings. This is vital for proper API routing and authentication.

Example Associated Domain Configuration:
demo-multi-region.entitlements

Follow Config iOS associated domain to add your iOS-associated domain to your Frontegg application.

Step 3: Implement Region Selection UI

The final step would be to implement a UI for users to select their region. This can be done in any way you see fit.
The example application uses a simple picker view to allow the user to select their region.

Important Considerations

  • Switching Regions: To switch regions, update the selection in UserDefaults. If issues arise, a re-installation of the application might be necessary.
  • Data Isolation: Ensure data handling and APIs are region-specific to prevent data leakage between regions.
Select EU RegionSelect US Region
eu-region-example.gifus-region-example.gif

Example Region Selection UI:

import SwiftUI
import FronteggSwift

struct SelectRegionView: View {
    @EnvironmentObject var fronteggAuth: FronteggAuth
    
    var body: some View {
        VStack(alignment: .leading) {
            Text("Welcome to MyApp")
                .font(.largeTitle)
            
            Text("Select your region:")
                .padding(.top, 8)
                .padding(.bottom, 20)
                .font(.title2)
            
            
            ForEach(fronteggAuth.regionData, id: \.key.self) { item in
                Button(action: {
                    FronteggApp.shared.initWithRegion(regionKey: item.key)
                }) {
                    VStack(alignment: .leading) {
                        Text("Region - \(item.key.uppercased())")
                            .font(.title2)
                            .padding(.bottom, 1)
                        Text("\(item.baseUrl)")
                            .font(.caption)
                            .tint(.black)
                            .padding(.bottom, 8)
                    }
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                .contentShape(Rectangle())
            }
            
            Spacer()
            
        }
        .padding()
        .navigationTitle("Region")
    }
}