amplify-swift icon indicating copy to clipboard operation
amplify-swift copied to clipboard

feat(auth): Keychain Sharing (No App Reload Required)

Open yaroluchko opened this issue 6 months ago • 6 comments

Issue #

https://github.com/aws-amplify/amplify-swift/issues/2508 https://github.com/aws-amplify/amplify-swift/issues/3277

Description

This allows Amplify Swift developers to set the access group they would like the auth session to be shared on. This PR, as opposed to this PR, does not require the other app with which the auth session is being shared with to be reloaded. This helps immensely when writing a product with app extensions.

Changes made

AWSCognitoCredentialAuthCredentialStore now uses access group to create keychain instance with said access group. If an access group is specified:

  • a different keychain service is used, specifically for shared items.
  • fetchAuthSession reconfigures the plugin when called, so that app reload is not required

Migration:

  • Amplify developers can specify if they want migration to happen by setting the migrateKeychainItemsOfUserSession to true within the accessGroup struct
  • migration involves moving any auth keychain items from the old access group (old access group name is stored in UserDefaults) to the new access group
  • migration is a batched operation, and the items will no longer be accessible from the old access group

Usage

Migrating to a Shared Keychain

To use a shared keychain:

  1. In Xcode, go to Project Settings → Signing & Capabilities
  2. Click +Capability
  3. Add Keychain Sharing capability
  4. Add a keychain group
  5. Repeat for all apps for which you want to share auth state, adding the same keychain group for all of them

To move to the shared keychain using this new keychain access group, specify the accessGroup parameter when instantiating the AWSCognitoAuthPlugin. If a user is currently signed-in, they will be logged out when first using the access group:

let accessGroup = AccessGroup(name: "\(teamID).com.example.sharedItems")
let secureStoragePreferences = AWSCognitoSecureStoragePreferences(
  accessGroup: accessGroup)
try Amplify.add(
  plugin: AWSCognitoAuthPlugin(
    secureStoragePreferences: secureStoragePreferences))
try Amplify.configure()

If you would prefer the user session to be migrated (which will allow the user to continue to be signed-in), then specify the migrateKeychainItemsOfUserSession boolean in the AccessGroup struct to be true like so:

let accessGroup = AccessGroup.none(migrateKeychainItemsOfUserSession: true)
let secureStoragePreferences = AWSCognitoSecureStoragePreferences(
  accessGroup: accessGroup)
try Amplify.add(
  plugin: AWSCognitoAuthPlugin(
    secureStoragePreferences: secureStoragePreferences))
try Amplify.configure()

Sign in a user with any sign-in method within one app that uses this access group. After reloading another app that uses this access group, the user will be signed in. Likewise, signing out of one app will sign out the other app after reloading it.

Migrating to another Shared Keychain

To move to a different access group, update the name parameter of the AccessGroup to be the new access group. Set migrateKeychainItemsOfUserSession to true to migrate an existing user session under the previously used access group.

Migrating from a Shared Keychain

If you’d like to stop sharing state between this app and other apps, you can set the access group to be AccessGroup.none or AccessGroup.none(migrateKeychainItemsOfUserSession: true) if you’d like the session to be migrated.

General Checklist

  • [x] Added new tests to cover change, if needed
  • [x] Build succeeds with all target using Swift Package Manager
  • [x] All unit tests pass
  • [x] All integration tests pass
  • [x] Security oriented best practices and standards are followed (e.g. using input sanitization, principle of least privilege, etc)
  • [x] Documentation update for the change if required
  • [x] PR title conforms to conventional commit style
  • [x] New or updated tests include Given When Then inline code documentation and are named accordingly testThing_condition_expectation()
  • [x] If breaking change, documentation/changelog update with migration instructions

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

yaroluchko avatar Aug 12 '24 23:08 yaroluchko