AWS: How to properly authenticate a user against Cognito Pool and use it for Cognito Federated Identity?
<p>I am working on an app which will use two authentication providers:</p>

<ul>
<li>Facebook</li>
<li>Cognito User Pool</li>
</ul>

<p>With the former, I have no issues, everything works as intended. However, while setting up the authentication with Cognito User Pools, I am hitting one wall after the other. I am using AWS SDK 2.4.9, XCode 8 and Swift 3.</p>

<p>I am aware that there are a lot of questions have already been asked, and a lot of "guides" are out there. However, a lot of them are answered/made for outdated docs and SDK. Even the official AWS documentation is out of date.</p>

<p>The authentication steps that I am going through are as follows:</p>

<p><strong>1. Configure the initial cognito pool</strong></p>

<pre><code>///  Set the default service configuration
let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.usEast1, credentialsProvider: nil)
AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration

/// Create a pool configuration and register it for a specific key to use later
let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: appClientID, clientSecret: appClientSecret, poolId: poolID)  
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPool(with: poolConfiguration, forKey: poolKey)

/// Create a pool for a specific predefined key
pool = AWSCognitoIdentityUserPool(forKey: poolKey)
</code></pre>

<p><strong>2. Authenticate the user against Cognito User Pool</strong></p>

<pre><code>  user.getSession(username, password: password, validationData: nil).continue({ (task) -&gt; AnyObject? in

        if let error = task.error as? NSError {
            completionHandler(error)
            return nil
        }

        let session = task.result! as AWSCognitoIdentityUserSession
        let token = session.idToken!.tokenString

        let tokens : [NSString:NSString] = ["cognito-idp.us-east-1.amazonaws.com/\(self.poolID!)" as NSString : token as NSString]
        let identityProvider = CognitoPoolIdentityProvider(tokens: tokens)

        let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .usEast1, identityPoolId: self.identityPoolID, identityProviderManager: identityProvider)

        ///  Set the default service configuration
        let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.usEast1, credentialsProvider: credentialsProvider)
        AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration

        credentialsProvider.getIdentityId().continue({ (task) -&gt; AnyObject? in
            completionHandler(task.error as NSError?)
            return nil
        })

        return nil
    })
</code></pre>

<p><strong>3. The CognitoPoolIdentityProvider class</strong></p>

<pre><code>    class CognitoPoolIdentityProvider : NSObject, AWSIdentityProviderManager {

      var tokens : NSDictionary = [:]

      init(tokens: [NSString : NSString]) {
           self.tokens = tokens as NSDictionary
      }

      @objc func logins() -&gt; AWSTask&lt;NSDictionary&gt; {
           return AWSTask(result: tokens)
      }

    }
</code></pre>

<p><strong>4. Storing data to Cognito Federated Identity</strong></p>

<p>All this passes without any errors. However, now I want to store the data that I have pulled from Cognito Pool to a specific Cognito Federated Identity Dataset, so I am calling: <code>userProfile.synchronize().continue</code> and I am getting the following results:</p>

<blockquote>
  <p>getCredentialsWithCognito:authenticated:customRoleArn:]_block_invoke |
  GetCredentialsForIdentity failed. Error is [Error
  Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)"
  UserInfo={__type=NotAuthorizedException, message=Access to Identity
  'us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' is forbidden.}]</p>
  
  <p>2016-11-10 10:27:16.947365 xxxxxxxx[19867:5614838] AWSiOSSDK v2.4.11
  [Error] AWSIdentityProvider.m line:304 |
  __52-[AWSCognitoCredentialsProviderHelper getIdentityId]_block_invoke.255 | GetId failed. Error is [Error
  Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)"
  UserInfo={__type=NotAuthorizedException, message=Unauthenticated
  access is not supported for this identity pool.}] 2016-11-10
  10:27:16.947726 xxxxxxxx[19867:5614838] AWSiOSSDK v2.4.11 [Error]</p>
  
  <p>AWSCredentialsProvider.m line:577 |
  __44-[AWSCognitoCredentialsProvider credentials]_block_invoke.352 | Unable to refresh. Error is [Error
  Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)"
  UserInfo={__type=NotAuthorizedException, message=Unauthenticated
  access is not supported for this identity pool.}] 2016-11-10
  10:27:16.948452 xxxxxxxx[19867:5614838] AWSiOSSDK v2.4.11 [Error]</p>
  
  <p>AWSCognitoDataset.m line:352 | __30-[AWSCognitoDataset
  syncPull:]_block_invoke | Unable to list records: Error
  Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)"
  UserInfo={__type=NotAuthorizedException, message=Unauthenticated
  access is not supported for this identity pool.} [10:27:16]:
  saveSettings AWS task error: The operation couldn’t be completed.
  (com.amazonaws.AWSCognitoIdentityErrorDomain error 8.)</p>
</blockquote>

<p>After changing the log level, I can see the following:</p>

<blockquote>
  <p>//REQUEST </p>
  
  <p>2016-11-10 10:33:08.095735 xxxxxxxx[19874:5616142] AWSiOSSDK
  v2.4.11 [Debug] AWSURLSessionManager.m line:543 |
  -[AWSURLSessionManager printHTTPHeadersAndBodyForRequest:] | Request body: {"IdentityId":"us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"}</p>
  
  <p>//RESPONSE </p>
  
  <p>2016-11-10 10:33:08.714268 xxxxxxxx[19874:5616154]
  AWSiOSSDK v2.4.11 [Debug] AWSURLSessionManager.m line:553 |
  -[AWSURLSessionManager printHTTPHeadersForResponse:] | Response headers: {
      Connection = "keep-alive";
      "Content-Length" = 129;
      "Content-Type" = "application/x-amz-json-1.1";
      Date = "Thu, 10 Nov 2016 09:33:08 GMT";
      "x-amzn-ErrorMessage" = "Access to Identity 'us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx' is forbidden.";
      "x-amzn-ErrorType" = "NotAuthorizedException:";
      "x-amzn-RequestId" = "b0ac6fb0-a728-11e6-8413-1fdb846185bb"; }</p>
</blockquote>

<p>The above request is the GetID API call. Clearly, it does not match the request format from the AWS Docs: <a href="http://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetId.html" rel="noreferrer">http://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetId.html</a>.</p>

<p>According to the AWSServiceManager class we have this:</p>

<pre><code>/**
 The default service configuration object. This property can be set only once, and any subsequent setters are ignored.
 */
@property (nonatomic, copy) AWSServiceConfiguration *defaultServiceConfiguration;
</code></pre>

<p>This means that setting the new service configuration is pointless, but I see no other way to refresh the credentials that I have obtained through the Cognito User Pool authentication.</p>

<p>That's pretty much it. Any ideas?</p>

<p>Thanks</p>