Amplifying AWS Tutorials: Building a Social Notes App with "Sign in with Apple" and AWS Pinpoint Analytics
Published: 2023-11-11 05:15:25

---
title: Amplifying AWS Tutorials: Building a Social Notes App with "Sign in with Apple" and AWS Pinpoint Analytics
published: true
date: 2023-08-01 00:24:33 UTC
tags: 
canonical_url: https://matt.martz.codes/amplifying-aws-tutorials-building-a-social-notes-app-with-sign-in-with-apple-and-aws-pinpoint-analytics
---

For the 2023 [AWS Amplify](https://aws.amazon.com/pm/amplify/?sc_channel=el&trk=bc603709-686b-4e27-b79f-07e5de3686ec) + [Hashnode](https://hashnode.com/?source=aws-amplify-2023) Hackathon, I wanted to take a closer look into iOS development and take the [introductory iOS notes app from AWS Amplify's tutorial](https://aws.amazon.com/getting-started/hands-on/build-ios-app-amplify/) to the next level by incorporating powerful features like federated login via [Apple's "Sign in with Apple"](https://aws.amazon.com/blogs/mobile/federating-users-using-sign-in-with-apple-and-aws-amplify-for-swift/) Then we'll add some easy Analytics to our app with AWS Pinpoint.

While AWS's initial tutorial covered basic username/password authentication... users appreciate convenience and security. To support this, we'll add "Sign in with Apple" support, which offers users a seamless and privacy-focused login option. With "Sign in with Apple," users can authenticate with their Apple ID and stay in control of their personal information (including giving them the ability to hide their email).

A successful app requires understanding user behavior and optimizing user experiences. That's where AWS Pinpoint Analytics comes into play. I'll demonstrate how to integrate AWS Pinpoint into the notes app, enabling us to collect critical user engagement data. With this newfound insight, we can analyze user interactions, monitor feature adoption, and make data-driven decisions to enhance the app's performance.

_AWS Amplify is a comprehensive development platform offered by Amazon Web Services (AWS) that simplifies the process of building web and mobile applications. It provides developers with a set of tools, services, and libraries to accelerate the development of cloud-powered applications._

This tutorial assumes you are familiar with the basics of AWS Amplify, including authentication setup and working with the Amplify Storage component. **If you're new to these concepts, I recommend checking out the** [**original AWS Amplify tutorial**](https://aws.amazon.com/getting-started/hands-on/build-ios-app-amplify) **to get up to speed.**

The code for this project is located here: [https://github.com/martzcodes/blog-amplifyhackathon-ios-2023](https://github.com/martzcodes/blog-amplifyhackathon-ios-2023)

## Updating the App to use "Sign in with Apple"

Amplify and Apple make it really easy to incorporate "Sign in with Apple" (SIWA) into your applications. SIWA allows you to federate users into an Amazon Cognito identity pool using the AWS Amplify Libraries for Swift. By federating a user into a Cognito identity pool, it allows us to use temporary AWS IAM credentials for the users based on the identity token that Apple provides us. In doing so, we can use those AWS IAM credentials to access other services like Amazon S3, AppSync and Pinpoint.

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 allow them to access other services like Amazon S3 and Amazon DynamoDB.

First, we'll update amplify's auth to use Apple's provider. Below is the full list of answers when running `amplify update auth`:

```
$ amplify update auth
 What do you want to do? Walkthrough all the auth configurations
 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)
 Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) Yes
 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

 You've opted to allow users to authenticate via Sign in with Apple. If you haven't already, you'll need to go to https://developer.apple.com/account/#/welcome and configure Sign in with Apple.

 Enter your Bundle Identifier for your identity pool: <your app bundle id from apple>
 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
 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?
 Do you want to use an OAuth flow? No
? Do you want to configure Lambda Triggers for Cognito? Yes
? Which triggers do you want to enable for Cognito

```

Identity pools do NOT use Cognito User Groups... they use AWS IAM-based access. In order to make use of these for our app, we need to switch AWS AppSync to use IAM auth instead of Cognito User Groups. Let's run `amplify update api`. Below are the full answers for this section:

```
amplify update api
? Select from one of the below mentioned services: GraphQL
...
? Select a setting to edit Authorization modes
? Choose the default authorization type for the API IAM
? Configure additional auth types? No

```

Before we can push these changes, we need to update our `schema.graphql`. It was using auth based on Cognito Pools, but we need to switch it to IAM-based auth. For demo sake, we also want to enable guests (unauthenticated users) to also read notes. We'll update the `schema.graphql` file to:

```
type NoteData
@model
@auth(
    rules: [
      { allow: public, provider: iam, operations: [read] }
      { allow: private, provider: iam, operations: [read, create, update, delete] }
    ]
  ) {
    id: ID!
    name: String!
    description: String
    image: String
}

```

- `{ allow: public, provider: iam, operations: [read] }` gives guests read access

- `{ allow: private, provider: iam, operations: [read, create, update, delete] }` gives logged in users full CRUD access

With the `schema.graphql` updated, we can run `amplify codegen models` to regenerate the APIs.

With these changes, we can run `amplify push` and our backend will update to reflect these new changes. Next, we'll need to modify some of the swift code.

Instead of using `Amplify.Auth.signInWithWebUI` we need to use the `SignInWithApple` button and then make a call to `federateToIdentityPool`. `SignInWithApple` is a capability provided by Apple. Once signed in, it provides an identity token that is used by `federateToIdentityPool`

In `ContentView.swift`:

```
// add this to the top of the file
import AuthenticationServices

// In the ContentView view:
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
                }
        guard let tokenString = String(data: identityToken, encoding: .utf8) else {
            return
        }
        Backend.shared.federateToIdentityPools(with: tokenString)
        self.userData.isSignedIn = true;
    case .failure(let error):
        print(error)
    }
}

// replace the original sign in button with:
SignInWithAppleButton(
    onRequest: configureRequest,
    onCompletion: handleResult
)
.frame(maxWidth: 300, maxHeight: 45)

```

`SignInWithAppleButton` triggers the SIWA capability by Apple. `configureRequest` ensures that the email is returned as part of the scope of the `identityToken`. On completion then parses the `identityToken` and sends it to our `Backend.swift` service.

In `Backend.swift` the `Amplify.Auth` plugin calls `federateToIdentityPool`:

```
func federateToIdentityPools(with tokenString: String) {
    guard
        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)
        }
    }
}

```

In this version of our code, we also have an auth listener that triggers UI updates based on session events. The auth listener in our `Backend.swift` file looks like this now:

```
public func listenAuthUpdate() async -> AsyncStream<AuthStatus> { 
    return AsyncStream { continuation in
        continuation.onTermination = { @Sendable status in
                   print("[BACKEND] streaming auth status terminated with status : \(status)")
        }

        // listen to auth events.
        // see https://github.com/aws-amplify/amplify-ios/blob/master/Amplify/Categories/Auth/Models/AuthEventName.swift
        let _ = Amplify.Hub.listen(to: .auth) { payload in            
            print(payload.eventName)
            switch payload.eventName {
            case "Auth.federatedToIdentityPool":
                print("User federated, update UI")
                continuation.yield(AuthStatus.signedIn)
                Task {
                    await self.updateUserData(withSignInStatus: true)
                }
            case "Auth.federationToIdentityPoolCleared":
                print("User unfederated, update UI")
                continuation.yield(AuthStatus.signedOut)
                Task {
                    await self.updateUserData(withSignInStatus: false)
                }
            case HubPayload.EventName.Auth.sessionExpired:
                print("Session expired, show sign in aui")
                continuation.yield(AuthStatus.sessionExpired)
                Task {
                    await self.updateUserData(withSignInStatus: false)
                }
            default:
                print("\(payload)")
                break
            }
        }
    }
}

```

For federation events, the events end up being `Auth.federatedToIdentityPool` and `Auth.federationToIdentityPoolCleared`.

## Adding AWS Pinpoint for App Analytics

Next, we want to see what our users are doing in our Notes app and see if they're really making use of the "new" image upload feature.

First, we'll need to update amplify by running `amplify add analytics`:

```
amplify add analytics
? Select an Analytics provider Amazon Pinpoint
 Provide your pinpoint resource name: amplifypushup

```

Then we'll run `amplify push`.

We'll need to [add the Amplify Analytics libraries to our app](https://docs.amplify.aws/lib/analytics/getting-started/q/platform/ios/#view-analytics-console) by making sure the `AWSPinpointAnalyticsPlugin` is installed. And then we'll add the initialization in our Backend.swift file:

```
private init() {
  // initialize amplify
  do {
      try Amplify.add(plugin: AWSCognitoAuthPlugin())
      try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: AmplifyModels()))
      try Amplify.add(plugin: AWSS3StoragePlugin())
      try Amplify.add(plugin: AWSPinpointAnalyticsPlugin()) // <-- add this
      try Amplify.configure()
      print("Initialized Amplify");
  } catch {
    print("Could not initialize Amplify: \(error)")
  }

```

If we want to track how popular our image upload feature is, we can add an event:

```
let properties: AnalyticsProperties = [
    "eventPropertyStringKey": "eventPropertyStringValue",
    "eventPropertyIntKey": 123,
    "eventPropertyDoubleKey": 12.34,
    "eventPropertyBoolKey": true
]

let event = BasicAnalyticsEvent(
    name: "imageUploaded",
    properties: properties
)

try Amplify.Analytics.record(event: event)

```

You can also emit events related to authentication that Pinpoint will automatically track:

- `_userauth.sign_in`

- `_userauth.sign_up`

- `_userauth.auth_fail`

## Conclusion

In my quest to elevate the capabilities of AWS Amplify tutorials, I ventured into iOS development for the 2023 [AWS Amplify](https://aws.amazon.com/pm/amplify/?sc_channel=el&trk=bc603709-686b-4e27-b79f-07e5de3686ec) + [Hashnode](https://hashnode.com/?source=aws-amplify-2023) Hackathon. Building upon the introductory iOS notes app tutorial provided by AWS Amplify, I took the app to the next level by incorporating sought-after features like "Sign in with Apple" and AWS Pinpoint Analytics.

The inclusion of "Sign in with Apple" as a federated login option significantly enhances the app's authentication experience. Users can now seamlessly log in with their Apple ID, ensuring both convenience and privacy. This advanced authentication option empowers users to stay in control of their personal information, including the ability to hide their email.

In addition to empowering users with a better way to sign-in, I integrated AWS Pinpoint Analytics into the notes app. By leveraging AWS Pinpoint's analytical capabilities, we gained valuable insights into user engagement and behavior. This data-driven approach allows us to analyze user interactions, monitor feature adoption, and make informed decisions to optimize the app's performance and user experience.

As you explore the code and implement these advanced features, I encourage you to further experiment and customize the app to suit your specific use case and preferences. Remember to refer to the [code repository](https://github.com/martzcodes/blog-amplifyhackathon-ios-2023) for detailed implementations.

Thank you for joining me on this amplified journey to enhance AWS tutorials. With "Sign in with Apple" and AWS Pinpoint Analytics at your fingertips, you're equipped to build robust and engaging mobile apps that connect users with seamless authentication and actionable insights.