Front-End Web & Mobile
Federating Users using Sign in with Apple and AWS Amplify for Swift
In many mobile apps, users are offered different ways to authenticate with the app like providing a username and password as well as offering options to sign in with a social provider like Amazon, Facebook, Google, and Apple. When authenticating with a social provider, the user goes through the provider’s auth flow and, in return, the provider gives the client app an identity token as proof that the user has successfully authenticated.
This article will show you how to use Sign in with Apple (SIWA) to retrieve an identity token and federate the user in an Amazon Cognito identity pool using the AWS Amplify Libraries for Swift. Federating a user in an identity pool provides them with credentials that allows them to access other services like Amazon S3 and Amazon DynamoDB.
Setup Sign in with Apple
In Xcode, navigate to the Signing & Capabilities tab and add Sign in with Apple:
In ContentView.swift
add the following import statement to the top:
import AuthenticationServices
The Sign in with Apple button requires two callbacks: one that configures the request and another that handles the response. Add the following functions to the ContentView
:
func configureRequest(_ request: ASAuthorizationAppleIDRequest) {
request.requestedScopes = [.email]
}
func handleResult(_ result: Result<ASAuthorization, Error>) {
switch result {
case .success(let authorization):
guard
let credential = authorization.credential as? ASAuthorizationAppleIDCredential,
let identityToken = credential.identityToken
else { return }
case .failure(let error):
print(error)
}
}
Next, in the body
of the ContentView
, add the Sign in with Apple button:
SignInWithAppleButton(
onRequest: configureRequest,
onCompletion: handleResult
)
.frame(maxWidth: 300, maxHeight: 45)
If you were to build and run the app on a device now, you would be able to go through the Sign in with Apple flow. However, Amplify needs to be setup before being able to take the identity token from the SIWA process to federate the user.
Setup Amplify Project
I will be using the Amplify CLI to create the Amplify project in the root directory of my iOS project, but you can use Amplify Studio if you’re more comfortable with that.
In the root directory of your Xcode project, run the following command in the terminal:
amplify init
I will use the default configuration for an iOS project. You can see the values I selected in the following snippet:
? Enter a name for the project FederateUserSIWA
The following configuration will be applied:
Project information
| Name: FederateUserSIWA
| Environment: dev
| Default editor: Visual Studio Code
| App type: ios
? Initialize the project with the above configuration? Yes
Using default provider awscloudformation
? Select the authentication method you want to use: AWS profile
? Please choose the profile you want to use default
✔ Help improve Amplify CLI by sharing non sensitive configurations on failures (y/N) · no
Once your Amplify project in successfully created, you must use the Amplify CLI to configure the Auth category since federating users with a social provider requires a manual configuration.
Enter the following command in the terminal:
amplify add auth
Answer the prompts with the following values:
? Do you want to use the default authentication and security configuration?
Manual configuration
? Select the authentication/authorization services that you want to use:
User Sign-Up, Sign-In, connected with AWS IAM controls (Enables per-user Storage features for images or other content, Analytics, and more)
? Provide a friendly name for your resource that will be used to label this category in the project:
federateusersiwa6c7eb14d6c7eb14d
? Enter a name for your identity pool.
federateusersiwa6c7eb14d_identitypool_6c7eb14d
? Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM)
No
? Do you want to enable 3rd party authentication providers in your identity pool?
Yes
? Select the third party identity providers you want to configure for your identity pool:
Apple
? Enter your Bundle Identifier for your identity pool:
com.kiloloco.Federate-User-SIWA
? Provide a name for your user pool:
federateusersiwa6c7eb14d_userpool_6c7eb14d
? How do you want users to be able to sign in?
Username
? Do you want to add User Pool Groups?
No
? Do you want to add an admin queries API?
No
? Multifactor authentication (MFA) user login options:
OFF
? Email based user registration/forgot password:
Enabled (Requires per-user email entry at registration)
? Specify an email verification subject:
Your verification code
? Specify an email verification message:
Your verification code is {####}
? Do you want to override the default password policy for this User Pool?
No
? What attributes are required for signing up?
Email
? Specify the app's refresh token expiration period (in days):
30
? Do you want to specify the user attributes this app can read and write?
No
? Do you want to enable any of the following capabilities?
No
? Do you want to use an OAuth flow?
No
? Do you want to configure Lambda Triggers for Cognito?
No
With the Auth category configured, it’s time to push your configuration to the backend. Run the following command:
amplify push
The Amplify CLI will show which resources have been created. It should look similar to the snippet below:
┌──────────┬──────────────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin │
├──────────┼──────────────────────────────────┼───────────┼───────────────────┤
│ Auth │ federateusersiwa6c7eb14d6c7eb14d │ Create │ awscloudformation │
└──────────┴──────────────────────────────────┴───────────┴───────────────────┘
If everything looks correct, hit Enter to continue. Once the configuration has been successfully deployed, you will see the following output in the terminal:
Deployment completed.
Add Amplify as a Dependency
Now it’s time to open Xcode and add Amplify as a dependency for the iOS project. Open the Search Packages screen (File > Add Packages…
):
Enter the Amplify Libraries for Swift repo URL (https://github.com/aws-amplify/amplify-swift/
) in the search bar at the top right. Select Up to Next Major Version for Dependency Rule and set the value to 2.0.0
, then click Add Package.
Select Amplify and AWSCognitoAuthPlugin as the package products and click Add Package.
You will now see Amplify and its dependencies added to the navigation bar in Xcode.
Configure Amplify
If the two configuration files have not been added to your Xcode project, open Finder, navigate to the root directory of your project, then drag and drop both amplifyconfiguration.json
and awsconfiguration.json
into the Xcode Navigation pane.
Open the <YOUR_PROJECT>App.swift
file and add the following import statements to the top:
import Amplify
import AWSCognitoAuthPlugin
Inside the <YOUR_PROJECT>App
object, add the following function to configure Amplify:
func configureAmplify() {
do {
try Amplify.add(plugin: AWSCognitoAuthPlugin())
try Amplify.configure()
print("Successfully configured Amplify")
} catch {
print("Failed to initialize Amplify:", error)
}
}
Add the following init
method to ensure that Amplify is configured as soon as the app is initialized:
init() {
configureAmplify()
}
Build and run. You will see the following output in the Xcode logs:
Successfully configured Amplify
Federating a User
Federating a user with Amplify requires using an escape hatch that gives access to the underlying AWS Swift SDK.
Navigate to the ContentView.swift
and add the following import statements at the top:
import Amplify
import AWSCognitoAuthPlugin
Next, add the function that will handle federating the user once an identity token is provided:
func federateToIdentityPools(with token: Data) {
guard
let tokenString = String(data: token, encoding: .utf8),
let plugin = try? Amplify.Auth.getPlugin(for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin
else { return }
Task {
do {
let result = try await plugin.federateToIdentityPool(
withProviderToken: tokenString,
for: .apple
)
print("Successfully federated user to identity pool with result:", result)
} catch {
print("Failed to federate to identity pool with error:", error)
}
}
}
Once the identity token has been converted to a String
, it is passed to the plugin to federate the user with the specified auth provider.
Lastly, add the following line of code to the success
case of handleResult
:
self.federateToIdentityPools(with: identityToken)
Build and run the app on a device. You will now be able to authenticate the user using Sign in with Apple and federate into the identity pool.
Once you’ve completed the Sign in with Apple process, you will see a similar output in the Xcode console:
Successfully federated user to identity pool with result: FederateToIdentityPoolResult(credentials: ["secretAccessKey": "NY*****5x", "sessionToken": "IQ*****==", "expiration": 2023-02-15 18:35:01 +0000, "accessKey": "AS*****FZ"], identityId: "us-east-1:0***9")
To verify that the user has been federated, you can run the following command in the terminal and select Identity Pool
:
amplify console auth
Your browser will open to the Amazon Cognito Federated Identities screen and you will be able to see one user that has authenticated using Sign in with Apple.
Conclusion
You have successfully setup an authentication flow for federating users via Sign in with Apple. If you don’t plan on maintaining this code, it is recommended that you run amplify delete
to remove all the resources that were generated for you during this tutorial.
As you use Amplify to build your next project, be sure to reach out on the GitHub repository, or through the Amplify Discord server under the #swift-help channel to help us prioritize features and enhancements.