I'm using AWS Cognito, integrated with iOS app through MobileHub to login via Facebook.
Everything works fine until I logout of existing identity and try to login with another FB account (or even with the same).
In this case I get this error, every time I call any AWS Lambda:
AWSiOSSDK v2.4.9 [Error] AWSCredentialsProvider.m line:577.
[AWSCognitoCredentialsProvider credentials].
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.}]
But if I terminate and restart the app, everything works correct again.
This error originates here:
From reading AWS SDK code I see, that it happens because cognito identity doesn't get logins from credential provider here:
I guess this is expected, since I've logged out. But the problem is that even after logging in to FB AWS still considers me Unauthorized. From similar questions on StackOverflow I see, that in past people set logins dictionary on AWSCognitoCredentialsProvider manually. But now this property is deprecated and other similar properties are readonly.
Here is my AWS setup in AppDelegate didFinishLaunchingWithOptions method:
let cred = AWSCognitoCredentialsProvider(regionType: .euWest1, identityPoolId: "POOLID")
let config = AWSServiceConfiguration(region: .euWest1, credentialsProvider: cred)
AWSServiceManager.default().defaultServiceConfiguration = config
if let config = config {
config.timeoutIntervalForRequest = 30
config.timeoutIntervalForResource = 30
config.maxRetryCount = 3
AWSLambdaInvoker.register(with: config, forKey: "key")
}
let mapperConfiguration = AWSDynamoDBObjectMapperConfiguration()
mapperConfiguration.saveBehavior = .updateSkipNullAttributes
AWSDynamoDBObjectMapper.register(with: config!, objectMapperConfiguration: mapperConfiguration, forKey: "updateObjectMapper")
And here is logout code:
AWSIdentityManager.defaultIdentityManager().logout { (result, error) in
if let cp = AWSServiceManager.default().defaultServiceConfiguration.credentialsProvider as? AWSCognitoCredentialsProvider {
cp.clearKeychain()
}
// Open login screen
}
Please note, that I tried both clearing keychain and not doing it. The result is the same.
I'd really appreciate any help!
Best regards,
Alex
Are you doing this in the implementation of the logins method?
- (AWSTask<NSDictionary<NSString *, NSString *> *> *)logins {
FBSDKAccessToken* fbToken = [FBSDKAccessToken currentAccessToken];
if(fbToken){
NSString *token = fbToken.tokenString;
return [AWSTask taskWithResult: #{ AWSIdentityProviderFacebook : token }];
}else{
return [AWSTask taskWithError:[NSError errorWithDomain:#"Facebook Login"
code:-1
userInfo:#{#"error":#"No current Facebook access token"}]];
}
}
More details.
Related
I have started integrating AWS Cognito User Pools into my app and the signup + login works (I have followed this tutorial: https://docs.aws.amazon.com/cognito/latest/developerguide/tutorial-integrating-user-pools-ios.html)
Now I'm struggling to properly integrate a Facebook login. This is what I do:
After the user has successfully signed in with facebook (using the facebook SDK), I'm getting the token and calling this function:
func signInFacebook(){
let customProviderManager = CustomIdentityProvider(tokens: nil)
self.credentialsProvider = AWSCognitoCredentialsProvider(
regionType:CognitoIdentityUserPoolRegion,
identityPoolId: CognitoIdentityPoolId,
identityProviderManager: customProviderManager)
let configuration = AWSServiceConfiguration(region:CognitoIdentityUserPoolRegion, credentialsProvider: self.credentialsProvider!)
AWSServiceManager.default().defaultServiceConfiguration = configuration
}
My CustomIdentityProvider class looks like this:
class CustomIdentityProvider: NSObject, AWSIdentityProviderManager {
var tokens : NSDictionary?
init(tokens: NSDictionary?) {
self.tokens = tokens
}
func logins() -> AWSTask<NSDictionary> {
if let fbToken = AccessToken.current?.authenticationToken {
return AWSTask(result: [AWSIdentityProviderFacebook: fbToken])
} else if let googleToken = GIDSignIn.sharedInstance().currentUser.authentication.idToken {
return AWSTask(result: [AWSIdentityProviderGoogle: googleToken])
}
return AWSTask(error:NSError(domain: "Social login", code: -1 , userInfo: ["Social login" : "No current social access token"]))
}
}
After signInFacebook() is called, I also call
self.credentialsProvider?.credentials().continueOnSuccessWith { (task:AWSTask<AWSCredentials>) -> Any? in
print("credentials: \(task.result!)")
return nil
}
and it prints some data in the log which looks fine.
But for some reason it doesn't seem to link properly everything together.
When I'm calling my backend to fetch some data, I usually do it like this:
I call self.user?.getSession().continueOnSuccessWith (user is an instance of AWSCognitoIdentityUser) and inside the closure I build the request where I put the token in the header. But if there are no tokens, the SDK shows my login screen. And this is what happens all the time. I would expect the user object to be updated with the correct tokens after the social login with Facebook has succeeded. What am I doing wrong?
I am creating an iOS application in Swift and I cannot find a way to search or get a list of Cognito Users with API. Per Amazon Documentation, it says to use the ListUsers API; however, it does not provide an endpoint to make the request and it is rather difficult to authenticate REST API requests with AWS so is there anyway to do this via iOS SDK? These are the parameters I would like to include in my Request.
[
"AttributesToGet": ["username" ],
"Filter": "username ^= \"micheal\"",
"Limit": 10,
"UserPoolId": "\(AWSCognitoUserPoolId)"
]
You have to search through the Mobile SDK.
For iOS
// Make a AWSCognitoListUsers Request
let getUsersRequest = AWSCognitoIdentityProviderListUsersRequest()
// Add the Parameters
//getUsersRequest?.attributesToGet = ["username"]
getUsersRequest?.userPoolId = AWSCognitoUserPoolId
// Make the Request
AWSCognitoIdentityProvider(forKey: AWSCognitoUserPoolId).listUsers(getUsersRequest!, completionHandler: { (response, error) in
// The response variable contains the Cognito Response
})
There is a a restful API endpoint to do it, because using the aws CLI you can do it. Command Line List User Pool
the aws CLI is a good way to check out if the interface can do it.
How to do it in the IOS SDK is another matter. There is little relationship (none) between the restful command set and the SDK method names. I think it is something you ask the CognitoIdentityProvider to do... I think it is listUsers or thereabouts, and I think you can list the pools as well.
+1 the other answer to this
Here is working code to fetch user lists fro Cognito.
//IAM User Key and Secret Key Required
let IAMUserKey = “****”
let IAMSecretKey = “****”
//Set Credentials
let credentialsProvider : AWSStaticCredentialsProvider = AWSStaticCredentialsProvider(accessKey: IAMUserKey, secretKey: IAMSecretKey)
let serviceConfiguration: AWSServiceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
//Register Identity Provider
AWSCognitoIdentityProvider.register(with: serviceConfiguration, forKey:UserPoolID)
//Request
let getUsersRequest = AWSCognitoIdentityProviderListUsersRequest()
getUsersRequest?.userPoolId = UserPoolID
//mentioned name of attributes in array - name, given_name, username, email and so on
getUsersRequest?.attributesToGet = ["name"]
//Add Value in filter you want to search
getUsersRequest?.filter = "name = \”jen\””
//It will search string in including string
//getUsersRequest?.filter = "name ^= \"jen\""
AWSCognitoIdentityProvider(forKey: UserPoolID).listUsers(getUsersRequest!,completionHandler: {(response, error) in
print("response:\(String(describing: response))")
print("error:\(String(describing: error))")
})
I am working on an app which will use two authentication providers:
Facebook
Cognito User Pool
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.
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.
The authentication steps that I am going through are as follows:
1. Configure the initial cognito pool
/// 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)
2. Authenticate the user against Cognito User Pool
user.getSession(username, password: password, validationData: nil).continue({ (task) -> 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) -> AnyObject? in
completionHandler(task.error as NSError?)
return nil
})
return nil
})
3. The CognitoPoolIdentityProvider class
class CognitoPoolIdentityProvider : NSObject, AWSIdentityProviderManager {
var tokens : NSDictionary = [:]
init(tokens: [NSString : NSString]) {
self.tokens = tokens as NSDictionary
}
#objc func logins() -> AWSTask<NSDictionary> {
return AWSTask(result: tokens)
}
}
4. Storing data to Cognito Federated Identity
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: userProfile.synchronize().continue and I am getting the following results:
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.}]
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]
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]
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.)
After changing the log level, I can see the following:
//REQUEST
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"}
//RESPONSE
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"; }
The above request is the GetID API call. Clearly, it does not match the request format from the AWS Docs: http://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetId.html.
According to the AWSServiceManager class we have this:
/**
The default service configuration object. This property can be set only once, and any subsequent setters are ignored.
*/
#property (nonatomic, copy) AWSServiceConfiguration *defaultServiceConfiguration;
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.
That's pretty much it. Any ideas?
Thanks
It seems from the error you are getting
Access to Identity 'us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' is forbidden
that the credentials that you obtained in the first part cannot access the identity you have made the synchronize call with so your identity probably changed.
I am in the process of implementing registration and login for my iOS app, using this project as an example:
https://github.com/awslabs/aws-sdk-ios-samples/tree/75ada5b6283b7c04c1214b2e1e0a6394377e3f2b/CognitoYourUserPools-Sample/Objective-C/CognitoYourUserPoolsSample
Previously, my app was able to access DynamoDB resources by using a credentials provider set up in my AppDelegate's didFinishLaunchingWithOptions method. However, after changing my project to include logging in and function like the example, I see the error:
"__type":"NotAuthorizedException","message":"Token is not from a supported provider of this identity pool."
The code setting the credentialsProviderin AppDelegate currently looks like this:
let serviceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: nil)
let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId:APP_CLIENT_ID, clientSecret: APP_CLIENT_SECRET, poolId: USER_POOL_ID)
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: USER_POOL_NAME)
let pool = AWSCognitoIdentityUserPool(forKey:USER_POOL_NAME)
pool.delegate = self
self.storyboard = UIStoryboard(name: "Main", bundle: nil)
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager:pool)
let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider)
I also cannot access any DynamoDB data through my app.
Based on the console output, the registration process seems to work correctly, although I'm unsure about the sign-in process. It occurred to me that I had changed the region from EU-West-1, where the DynamoDB resources were stored, to US-East-1. In order to account for this change, I repeated the same steps I had intially taken to allow my app to access DynamoDB:
I created Auth and Unauth roles, both with access to the same actions as the role which had previously worked, but for the EU-West-1 resources instead.
I set these roles to the user pool I created when setting up registration under "unauthenticated role" and "authenticated role".
In case it makes a difference, I should note that I did not use the exact same sign-in process outlined in the example project I linked. Instead, I used the explicit sign in process, like so:
let name = usernameField.text!
let user = pool!.getUser(name)
lock()
user.getSession(name, password: passwordField.text!, validationData: nil, scopes: nil).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: {
(task:AWSTask!) -> AnyObject! in
if task.error != nil {
self.sendErrorPopup("ERROR: Unable to sign in. Error description: " + task.error!.description)
} else {
print("Successful Login")
dispatch_async(dispatch_get_main_queue()){
self.performSegueWithIdentifier("mainViewControllerSegue", sender: self)
}
}
self.unlock()
return nil
})
The methods lock(), unlock(), and sendErrorPopup() are strictly UI-related methods that I made so that the beginning and end of the sign-in process would be more visually clear. The console output always reads "successful login", but I am wondering if this code actually signs the user in correctly, since the error message makes it sound like the user might not be properly authorized.
It occurred to me that the US-West tables might not have been set up correctly, but I experience the same problem even when trying to create new tables, so I don't think that's the issue. Are there steps I might have missed as far as giving the user access to DynamoDB? Has the process changed with AWS Cognito's new beta user pool system?
EDIT 2:
I fixed the previous issue, and for a while, my app was working fine. However, it has suddenly stopped loading DynamoDB data when I sign in, and shows the error message: invalid login token. Can't pass in a Cognito token. Currently, my AppData code looks like this:
let serviceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: nil)
let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId:APP_CLIENT_ID, clientSecret: APP_CLIENT_SECRET, poolId: USER_POOL_ID)
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: USER_POOL_NAME)
let pool = AWSCognitoIdentityUserPool(forKey:USER_POOL_NAME)
pool.delegate = self
self.storyboard = UIStoryboard(name: "Main", bundle: nil)
self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager:pool)
let manager = IdentityProviderManager(tokens: [NSString:NSString]())
self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager: manager)
let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider!)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
...and my sign-in code looks like this:
if locked { return }
trimRegistrationValues()
let name = usernameField.text!
let user = pool!.getUser(name)
lock()
user.getSession(name, password: passwordField.text!, validationData: nil, scopes: nil).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: {
(task:AWSTask!) -> AnyObject! in
if task.error != nil {
self.sendErrorPopup("ERROR: Unable to sign in. Error description: " + task.error!.description)
} else {
print("Successful Login")
let loginKey = "cognito-idp.us-east-1.amazonaws.com/" + USER_POOL_ID
var logins = [NSString : NSString]()
self.credentialsProvider!.identityProvider.logins().continueWithBlock { (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
print("ERROR: Unable to get logins. Description: " + task.error!.description)
} else {
if task.result != nil{
let prevLogins = task.result as! [NSString:NSString]
print("Previous logins: " + String(prevLogins))
logins = prevLogins
}
logins[loginKey] = name
let manager = IdentityProviderManager(tokens: logins)
self.credentialsProvider!.setIdentityProviderManagerOnce(manager)
self.credentialsProvider!.getIdentityId().continueWithBlock { (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
print("ERROR: Unable to get ID. Error description: " + task.error!.description)
} else {
print("Signed in user with the following ID:")
print(task.result)
dispatch_async(dispatch_get_main_queue()){
self.performSegueWithIdentifier("mainViewControllerSegue", sender: self)
}
}
return nil
}
}
return nil
}
}
self.unlock()
return nil
})
I haven't changed anything between my app working and not working. I did cause a "too many password resets" error while testing the password reset functionality, but the issue persisted even when I created a new user account on my app, so I don't think that's the cause. Am I handling login correctly? If so, where should I look for other possible causes to this issue?
That exception is usually thrown if you've given Cognito a login but have not enabled your identity pool to consume that login provider. If you haven't, go to the Cognito Federated Identities console and turn on whichever provider you are trying to use (looks like User Pools), and this error should go away.
If you're certain you have set that up, can you give a code snippet of how you're setting the logins?
The key that you set the ID token against in logins should be of the format cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID> not your USER_POOL_NAME. This blog along with the link in your post for our dev guide should explain the steps and code you need.
As for the solution to deprecated logins dictionary, you need to use this constructor to create the credentials provider. The identityProviderManager here should be an implementation of AWSIdentityProviderManager Protocol and the logins method should return the dictionary mapping for your provider name to the token. The credentials provider will call this method every time it needs the identity provider token. Check this answer for more details.
Thanks for the help in advance!
I am having some trouble getting Amazon Cognito to store/synchronize data properly.
On the dataset.synchronize() line (which does not store the data in Cognito), I get a large output error (with ID starred out) such as:
AWSCredentialsProvider.m line:429 | __73-[AWSCognitoCredentialsProvider
getCredentialsWithCognito:authenticated:]_block_invoke | GetCredentialsForIdentity
failed. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain
Code=10 "(null)" UserInfo={__type=NotAuthorizedException, message=Access to
Identity '*****' is forbidden.}]
The cognitoID is not nil, and returns properly (and matches the values I can read online)
For instance, after authenticating with Facebook, I perform the following:
if (FBSDKAccessToken.currentAccessToken() != nil)
{
let fbCognitoToken = FBSDKAccessToken.currentAccessToken().tokenString
credentialsProvider.logins = [AWSCognitoLoginProviderKey.Facebook.rawValue: fbCognitoToken]
// Retrieve your Amazon Cognito ID
credentialsProvider.getIdentityId().continueWithBlock { (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
print("Error: " + task.error!.localizedDescription)
}
else {
// the task result will contain the identity id
let cognitoId = task.result
//checking if cognito was successful, if true, sets success condition to true to prepare for segue into app
if cognitoId != nil{
print (cognitoId)
cognitoSuccess = true
let syncClient = AWSCognito.defaultCognito()
let dataset = syncClient.openOrCreateDataset("User_Data")
dataset.setString("test#test.com", forKey:"Email")
// credentialsProvider.refresh()
dataset.synchronize()
} }return nil}}
I can read data from Facebook correctly, and all authentication occurred correctly from what I can tell. I suspect there is something simple that is at the root here, but after spending several days, I cannot figure it out! Using the IAM checker in the AWS portal returns all "green checks" for Cognito functions, so I am sure this not a permissions issue on the server-side, either.
Thanks again for any insight you might have!
Edit:
Before the chunk of code above, I call:
let credentialsProvider = self.initializeCognito()
which runs (identity pool ID starred out):
func initializeCognito () -> AWSCognitoCredentialsProvider
{
let credentialsProvider = AWSCognitoCredentialsProvider(
regionType: AWSRegionType.USEast1, identityPoolId: "******")
let defaultServiceConfiguration = AWSServiceConfiguration(
region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
return credentialsProvider
}
That exception can be thrown when you're trying to get credentials for an authenticated id without giving any provider token linked to it. Cognito requires at least one to be given.
Can you check that you're including the facebook token during the GetCredentialsForIdentity call that's failing? If not, I'd guess that's your issue.
Edit:
Since you are using AWSCognito.defaultCognito(), it might help to follow the example on this docs page to make sure the sync client uses the right credentials provider:
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
Ended up figuring out the answer-- when I first set up AWS and was following some of Amazon's guides, I had placed code to create a new credentialsProvider in the application's App Delegate. I forgot about it, and then was trying later on to initialize another credentialsProvider. This confusion created the issues, and removing the initialization in App Delegate fixed the authentication problems.