I am currently unable to authorize users using AWS iOS SDK V2 using Facebook and Google+ as the provider.
I'm not sure if its my setup on the AWS Developer Console, or whether its the code.
This is the role policy for the identity pools:
{
"Version": "2012-10-17",
"Statement": [{
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*"
],
"Effect": "Allow",
"Resource": ["*"]
}]
I do receive an unauthorized Cognito ID but when I try to use either Facebook or Google+ provider authentication, it does not work.
Once the Facebook login returns I can successfully use the user properties to extract the profile picture, name and email address. I then get the token (yes it is a very long string of characters) from the Facebook session and use it in the deviceID class:
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
user:(id<FBGraphUser>)user {
//Populate viewcontoller with Facebook data
self.profilePictureView.profileID = user.id;
NSRange range = [user.name rangeOfString:@" "];
self.firstName.text = [user.name substringToIndex:range.location];
self.lastName.text = [user.name substringFromIndex:range.location+1];
self.emailAddress.text = [user objectForKey:@"email"];
//Get Facebook token, set then get Cognito device ID - in DeviceId class
NSString *token = FBSession.activeSession.accessTokenData.accessToken;
DeviceId *myDeviceId = [DeviceId sharedInstance];
cognitoDeviceId = [myDeviceId setFacebookToken:token];
}
The DeviceID class implementation is shown below:
#import "DeviceId.h"
#import <AWSiOSSDKv2/AWSCore.h>
#import <AWSCognitoSync/Cognito.h>
@implementation DeviceId
static NSString *cognitoId;
static DeviceId *_sharedInstance;
static AWSCognitoCredentialsProvider *credentialsProvider;
static AWSServiceConfiguration *configuration;
+ (DeviceId *) sharedInstance
{
if (!_sharedInstance)
{
_sharedInstance = [[DeviceId alloc] init];
}
return _sharedInstance;
}
- (NSString *) getDeviceId
{
return cognitoId;
}
- (void) setDeviceId
{
/*
* AWS Cognito
*/
credentialsProvider = [AWSCognitoCredentialsProvider
credentialsWithRegionType:AWSRegionUSEast1
accountId:@"(accountID"
identityPoolId:@"(identityPool)"
unauthRoleArn:@"arn:aws:iam::(accountID):role/Cognito_(app)UsersUnauth_DefaultRole"
authRoleArn:@"arn:aws:iam::(accountID):role/Cognito_(app)UsersAuth_DefaultRole"];
configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSEast1
credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
// Retrieve the cognito ID.
cognitoId = credentialsProvider.identityId;
if (!cognitoId) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Identification Error"
message:@"Error on User Account."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
}
-(NSString *)setFacebookToken:(NSString*)token {
credentialsProvider.logins = @{ @(AWSCognitoLoginProviderKeyFacebook): token };
[self setDeviceId];
return cognitoId;
}
-(NSString *)setGooglePlusToken:(NSString*)token {
credentialsProvider.logins = @{ @(AWSCognitoLoginProviderKeyGoogle): token };
[self setDeviceId];
return cognitoId;
}
@end
I get no error message and the dashboard above never shows an authenticated user. The CognitoID never changes its value. Can someone tell me where the issue is?
EDIT: Updated DeviceId.m based on comments still returns nil for cognitoId
EDIT 2: Updated DeviceId.m to replace while loop checking if BFTask was finished to Bolts method waitUntilFinished.
#import "DeviceId.h"
#import <AWSiOSSDKv2/AWSCore.h>
#import <AWSCognitoSync/Cognito.h>
@implementation DeviceId
{
__block NSString *tempCognitoId;
}
static NSString *cognitoId;
static DeviceId *_sharedInstance;
static AWSCognitoCredentialsProvider *credentialsProvider;
static AWSServiceConfiguration *configuration;
+ (DeviceId *) sharedInstance
{
if (!_sharedInstance)
{
_sharedInstance = [[DeviceId alloc] init];
}
return _sharedInstance;
}
- (NSString *) getDeviceId
{
return cognitoId;
}
- (void) setDeviceId
{
/*
* AWS Cognito
*/
credentialsProvider = [AWSCognitoCredentialsProvider
credentialsWithRegionType:AWSRegionUSEast1
identityPoolId:@"Identity Pool ID"];
configuration = [AWSServiceConfiguration
configurationWithRegion:AWSRegionUSEast1
credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
BFTask *taskIdentity = [[credentialsProvider refresh] continueWithBlock:^id(BFTask *task){
if (task.error == nil)
{
tempCognitoId = credentialsProvider.identityId;
NSLog(@"cognitoId: %@", cognitoId);
}
else
{
NSLog(@"Error : %@", task.error);
}
return nil;
}];
[taskIdentity waitUntilFinished];
cognitoId = tempCognitoId;
}
-(NSString *)setFacebookToken:(NSString*)token {
credentialsProvider.logins = @{ @(AWSCognitoLoginProviderKeyFacebook): token };
BFTask *taskIdentity = [[credentialsProvider refresh] continueWithBlock:^id(BFTask *task){
if (task.error == nil)
{
tempCognitoId = credentialsProvider.identityId;
NSLog(@"cognitoId: %@", tempCognitoId);
}
else
{
NSLog(@"Error : %@", task.error);
}
return nil;
}];
[taskIdentity waitUntilFinished];
cognitoId = tempCognitoId;
return cognitoId;
}
-(NSString *)setGooglePlusToken:(NSString*)token {
credentialsProvider.logins = @{ @(AWSCognitoLoginProviderKeyGoogle): token };
BFTask *taskIdentity = [[credentialsProvider getIdentityId] continueWithBlock:^id(BFTask *task){
if (task.error == nil)
{
tempCognitoId = credentialsProvider.identityId;
NSLog(@"cognitoId: %@", tempCognitoId);
}
else
{
NSLog(@"Error : %@", task.error);
}
return nil;
}];
[taskIdentity waitUntilFinished];
cognitoId = tempCognitoId;
return cognitoId;
}
@end
I do realize that some may consider waiting for completion is bad practice but I need to be sure for testing purposes that cognitoId is returned "synchronously". After modifying the Facebook App ID, using this method the cognitoID is returned.
Edit 3: However, Google+ is failing before reaching deviceId.
- (void)finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error) {
_signInAuthStatus.text =
[NSString stringWithFormat:@"Status: Authentication error: %@", error];
NSLog(@"%@", error);
return;
}
NSString *idToken = [auth.parameters objectForKey:@"id_token"];
DeviceId *myDeviceId = [DeviceId sharedInstance];
[myDeviceId setGooglePlusToken:idToken];
}
The NSLog error prints: Error Domain=com.google.GooglePlusPlatform Code=-1 "The operation couldn’t be completed. (com.google.HTTPStatus error 400.)" The API & Auth Product Name and Current Email Address appear to be correct on the console.
Edit 4: Cognito Synch in another section of the code has now stopped working where it worked before:
AWSCognito *syncClient = [AWSCognito defaultCognito];
AWSCognitoDataset *dataset = [syncClient openOrCreateDataset:@"myDataSet"];
NSString *fullName = [dataset stringForKey:@"name"];
Fails on the first line with the error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[AWSEndpoint endpointWithRegion:service:]: unrecognized selector sent to class
Any help on these additional errors is appreciated.