I'm trying to understand how to sign in with a developer authenticated identity using AWS mobilehub's iOS SDK as recently AWS changed this SDK and I cannot find any documentation on this.
The sample app fails to shed any light on this.
I have a REST API to retrieve the cognito ID and Token but I'm not
sure what to do with them once I have this.
AWS has the following different classes that futher complicate the issue:
AWSCognitoCredentialsProvider (No longer available in new SDK),
AWSAbstractCognitoIdentityProvider (no longer available in new SDK)
There's now something called AWSAbstractCognitoIdentityProviderHelper..
These are handled by the AWSIdentityManager which is part of AWSMobileHubHelper.framework however AWSIdentityManager doesn't let you
set the credentials provider so I don't understand how I am meant to
interact with it in this regard.
Any tutorials, documentation, etc. would be much appreciated
Your question exposes certain terminology problems:
3 ways to use Cognito
You must understand that there are 3 different interface apis.
With respect to Identity and SignIn/Authentication (the topics of this question) aws-mobile-hub-helper (hereafter MHH) has an elegant design and works well. I would recommend anyone using Cognito start with the Mobile Hub site (or at least with aws-mobile-hub-helper). The MHH is basically a wrapper to the SDK and helps clarify and separate the issues of persistent federated identity and credentials/authorization for AWS services from issues of Identity, authentication and attributes/claims for that Identity.
The mobile-hub-helper is documented only in the .h files. These can be processed into documentation by appledocs, and the comments there are pretty good if you had an overview of the class structure (which does not exist but I will attempt to provide).
SDK Authentication Flow
The authentication flow documented by AWS, is an oversimplification and does not aid in understanding how the authentication is accomplished using the SDK and Mobile Hub Helper. The following diagrams attempt to convey how identity authentication(login) and authorization(credentials) to use AWS Services (like S3, and DynamoDB) works.
Cognito is a single name created by AWS to cover many functionalities and roles.
SDK class names are confusing. But with few exceptions, classes starting with AWSCognitoIdentity (but NOT AWSCognitoIdentityProvider) are about the credentialsProvider/IdentityProvider, classes starting with AWSCognitoIdentityProvider relate to Oauth/Open Id Connect providers and other distributed identity providers (facebook).
These terms are used loosely throughout the AWS documentation and marketing material. This is an attempt to sort out the terminology by grouping terms that are used interchangeably by AWS.
When the user authenticates, authenticating disables the unauthenticated identityId (the identityId will be permanently marked with DISABLED in the Logins array in the identityPool entry. You can see this in the Cognito console.) that is currently on the device. There is one exception: If this is the first time the authentication takes place for this Identity then the unauthenticated identityId is not abandoned but is associated with the Identity and used as the authenticated identityID going forward.
Merging multiple Identities (meaning usernames not IdentityId’s) from different Identity providers abandons (disables) one of the identityId's, and associates both Identities with the other identityId. Disabled Id’s get created whenever this happens. These abandoned identityId's are marked with DISABLED in the Logins array in the cognito identityPool.
In practice this process creates a reasonable use of unique identityIds with disabled ones only getting created when a user authenticates on a new device (It can be bothersome in testing as it creates a barrage of disabled and unused identityId’s as the tester logs out and in multiple times with multiple id’s). But in practice the common use case would not create this barrage of disabled identityIds. A user would:
Connect – get an unauthenticated id - authenticate – and use the same ID. No abandoned id is created.
AWSIdentityProviderManager is the protocol that manages federated AWSIdentityProviders
In mobile-hub-helper AWSIdentityManager is the AWSIdentityProviderManager
All it needs to do is return to credentials provider a logins dictionary, with providers name and ID Token. AWSIdentityManager only returns the providername and token for a single identity provider. It simply gets the name and token from the AWSSignInProvider and returns. (There is a fork with a modification that adds the ability to return all of the current logged in providers in the logins dictionary.)
As modified AWSIdentityManager maintains an NSDictionary called cachedLogins. Each new login adds an login (an identity provider name and id token) to the cache. Then logins always returns the whole loginCache. This is what supports identity merging.
When the credentials provider calls it’s associated AWSIdentityProviderManager logins method, and finds a list of logins instead of just one it will merge the identityId's for those logins in it’s database and disable the identityId of one of them. How does it know which ID goes with which login? The ID Token contains an encoded decryptable (paste the token into https://jwt.io to see for yourself) set of claims, one of which is the identity (ex: username)
Note: Even though you have an identityId that has multiple related logins, in Mobile Hub Helper you are only ever authenticated by one AWSSignInProvider. Credentials get associated with the merged identityId, but in mobile-hub-helper access to that identityId is always via the active AWSSignInProvider (authentication provider) even if you are logged with multiple identity providers. Your app can keep track of all of the AWSSignInProviders and access them independently of AWSIdentityManager, but from AWSIdentityManagers point of view you are logged in with one of them. In practice this has little impact (until you try to get "claims" like imageURL from different providers for instance).
About Merging Identities
Currently the AWSIdentityManager does not support identity merging. I have a forked repository https://github.com/BruceBuckland/aws-mobilehub-helper-ios from the github repository that adds that capability, and adds a Cognito User Pools Identity Provider AWSSignInProvider (AWSCUPIdPSignInProvider.swift).
You can probably think of all sorts of gotcha’s when merging identities.
What if I try to merge two identities from the same provider (wouldn’t the dictionary keys be the same?)
What if I try to merge two identities, each of which has a different identity from the same provider associated with it (and again they would create two entities with the same keys).
Cognito manages this beautifully and rejects attempts to merge
identites that cannot be merged. The rejection happens at login time (when you would try get credentials, the credentials provider will reject the logins dictionary that contains an un-mergeable identityId)
Where Cognito buries its data
Cognito stores a keychain on the device that contains the last identityId that was used. This is used by the credentialsProvider/identityProvider object upon a call to credentialsProvider.credentials (IOS SDK name) to re-use an existing identity (for example unauthenticated) and avoid creating unused identities unless the user truly is not going to log in or resume.
Mobile-Hub-Helper’s AWSSignInProvider’s and AWSIdentityManager store an indication of an open session state in NSUserDefaults. These are used to re-start the session if the app is terminated and restarted.
AWSSignInProvider’s store NSUserDefaults too, and sometimes in the IOS Keychain, for their own internal purposes (like retaining easy persistent access to a username or imageURL or token)