Sign in to websites in your SwiftUI app


Sign in to websites in your SwiftUI app

Many Swift apps require access to an online account. A person using your app must sign into a website to give your app access to the account. How do you let the person sign in from your app?

Apple provides a class, ASWebAuthenticationSession, to simplify signing into a website from an iOS or Mac app. When you create and start an instance of ASWebAuthenticationSession, a private browser window opens for someone to sign into a website. After signing in, ASWebAuthenticationSession takes you back to your app.

You must perform the following tasks to use ASWebAuthenticationSession in a SwiftUI app:

  • Add a custom URL type for your app.
  • Create a class for your login session.
  • Add a presentation anchor.
  • Create an ASWebAuthenticationSession instance.
  • Create a SwiftUI view to handle the sign in.

Create a custom URL type

When someone finishes logging in to the website, they should go back to your app. You must add a URL type to your app to go back to the app.

Select your app target from the project editor and click the Info button at the top of the project editor to add a URL type to the app.

Give your URL type a name in the Identifier text field. Enter the URL type in the URL Schemes text field. The URL type should take the following form:

appname://

Create a class for your login session

To use ASWebAuthenticationSession you must add a class to hold the login session.

import AuthenticationServices
class LoginSession: NSObject, 
  ObservableObject, 
  ASWebAuthenticationPresentationContextProviding {
  var webAuthSession: ASWebAuthenticationSession?
}

The ASWebAuthenticationSession class is part of the Authentication Services framework so you must import that framework.

The class must conform to the ASWebAuthenticationPresentationContextProviding protocol. Inheriting from NSObject is the easiest way to conform to the protocol.

Conforming to ObservableObject lets you pass the session to another SwiftUI view.

The class needs a property of type ASWebAuthenticationSession to run the login session.

Add a presentation anchor

The login session requires a presentation anchor, which is a window to show the login session so people can sign in. Add the following function to your login session class:

func presentationAnchor(for session: 
  ASWebAuthenticationSession) -> ASPresentationAnchor {
  return ASPresentationAnchor()
}

ASPresentationAnchor is an instance of UIWindow on iOS and an instance of NSWindow on Mac.

Create an ASWebAuthenticationSession instance

Now you can create an instance of ASWebAuthenticationSession. You must supply the following arguments:

  • The URL of the website to log in.
  • The callback URL, the URL to go when the login session finishes.
  • A completion handler closure (function) that runs when the session finishes successfully.

The callback URL is the custom URL type you created for the app, minus the ://.

appname

The following code creates the session:

webAuthSession = ASWebAuthenticationSession.init(
  url: websiteURL, 
  callbackURLScheme: callbackURL, 
  completionHandler: { (callback:URL?, error:Error?) in
  // Do what you need to after someone logs in.
})
// Run the session
webAuthSession?.presentationContextProvider = self
webAuthSession?.prefersEphemeralWebBrowserSession = true
webAuthSession?.start()

Add a login function to the LoginSession class and add this code to the function. You will have to add code for the websiteURL and callbackURL variables, as these depend on the website where you want to sign in and your app's custom URL.

You should use ephemeral web browser sessions. If you set prefersEphemeralWebBrowserSession to false, information from previous sessions will be available in the session.

If you need to make any async calls in the completion handler, wrap them in a Task block. ASWebAuthenticationSession does not support Swift’s async await concurrency features.

Task {
  // Put async calls here
}

Create a login view

After creating the class to handle the login session, you can create a SwiftUI view for people to sign in. The following code shows an example of a simple login view:

struct LoginView: View {
  @StateObject var session = LoginSession()
  @Environment(\.presentationMode) var presentationMode
	 
  var body: some View {
    VStack {
      Image(systemName: "person.circle")
        .resizable()
        .frame(width: 64, height: 64)
        .padding()
      Text("You need to sign in.")
        .padding()
      Button {
        login()
      } label: {
        Text("Sign In")
      }
    }
    .frame(width: 256, height: 256, alignment: .topLeading)
  }    
}
extension LoginView {
  func login() {
    session.login()
    presentationMode.wrappedValue.dismiss()
  }    
}

The view code uses the @StateObject property wrapper to store the login session because the session is a class that conforms to ObservableObject. The view has a Sign In button. When the person taps or clicks that button, the login session starts, and the person can sign in to the website.

Additional reading

The following articles provide more information:

Swift Dev Journal

Subscribe and get exclusive articles on Swift development, a free guide on moving from tutorials to making your first app, notices of sales on books, and anything I decide to add in the future.

Read more from Swift Dev Journal

Find the Code Causing Long SwiftUI Updates with Instruments Instruments comes with a SwiftUI instrument to find performance problems in your SwiftUI apps. This article shows how to use Instruments to find the code that causes long SwiftUI view updates. If you have never used Instruments, read the following article to learn how to profile your app with the SwiftUI instrument: Find the SwiftUI Views that Update the Most Using Instruments Finding Long Updates When you finish profiling your app,...

When you profile your app with the Allocations instrument, you may want to find the largest memory allocations your app makes. Take the following steps to find the largest memory allocations: Press Cmd-3 to open the allocations list. Click the Size column heading to sort the allocations by size. Choose All Heap Allocations from the Allocation Type menu in the bottom bar to hide virtual memory allocations. Your code doesn’t directly make virtual memory allocations. The Allocation Type menu is...

A common problem people run into when they start profiling their apps with Instruments is finding the code that is causing problems. Many instruments initially show general statistics instead of statistics about the code you wrote. For example the Allocations instrument initially shows the number of memory allocations and amount of allocated memory for hundreds of memory categories. If your app allocates a lot of memory, you want to find the code that allocates high amounts of memory. How do...