AWS Mobile Blog

Using the Amazon Cognito Credentials Provider

by Stefano Buliani | on | Permalink | Comments |  Share

Warning (Nov 2017): The content below is outdated. Updated content is forthcoming.

Amazon Cognito helps you create unique identifiers for your end users that are kept consistent across devices and platforms. Cognito also delivers temporary, limited-privilege credentials to your application to access AWS resources.

With Amazon Cognito your application can support unauthenticated guest users as well as users authenticated through a public identity provider, such as Facebook, Google or Login with Amazon.

Unauthenticated identities are tied to a device; this means the Cognito client SDK will keep the unique identifier generated for an end user consistent when that users accesses the service from the same device. Authenticated users, on the other hand, have a unique identifier that follows them across devices, even if they use different operating systems (iOS and Android).

Initialize the Amazon Cognito credentials provider

To use Amazon Cognito in your mobile application you need to include the new AWS Mobile SDK for iOS or Android—our developer resources page lists all of the AWS SDKs that support Amazon Cognito. The first step is to initialize the Cognito credentials provider—you can create a new Identity Pool from the Amazon Cognito management console—once you have completed the identity pool creation wizard the console will give you all the information you need to initialize the credentials provider.

The Cognito credentials provider is in charge of generating or retrieving a unique identifier for your end users and delivering temporary credentials to access your AWS resources.

iOS

// you need to import the AWSCore library from the AWS iOS SDK
#import <AWSiOSSDK/AWSCore.h>

// initialize the Cognito credentials provider with the values from
// your identity pool.
AWSCognitoCredentialsProvider *credentialsProvider = [AWSCognitoCredentialsProvider 
    credentialsWithRegionType:AWSRegionUSEast1
                    accountId:@"1234567890", // your AWS Account id          
               identityPoolId:@"us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", // your identity pool id        
                unauthRoleArn:@"arn:aws:iam::XXXXXXXXXX:role/YourRoleName",// an unauthenticated role ARN     
                  authRoleArn:@"arn:aws:iam::XXXXXXXXXX:role/YourRoleName" // an authenticated role ARN
];

Android

// import the CognitoCredentialsProvider object from the auth package
import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.regions.Regions;


// initialize a credentials provider object with your Activity’s context and
// the values from your identity pool 
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
    getContext(), // get the context for the current activity        
    "1234567890", // your AWS Account id     
    "us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX", // your identity pool id    
    "arn:aws:iam::XXXXXXXXXX:role/YourRoleName",// an authenticated role ARN
    "arn:aws:iam::XXXXXXXXXX:role/YourRoleName", // an unauthenticated role ARN
    Regions.US_EAST_1 //Region
);

When initialized for the first time in an application the Cognito credentials provider assumes it is dealing with an unauthenticated user. If it’s not the first time, and the credentials provider already has a cached identity on the device, it will try to load the existing identity. This may cause an error if the identity is linked to an authenticated user; the authenticated users section below explain how to set the authentication tokens in the credentials provider object.

Receiving the end user identity ID

When the credentials provider is initialized and the unique identifier for the end user is generated your application is notified by the Cognito client SDK. The iOS client SDK uses the Notification Center to call your app code; the Android SDK does that through an IdentityChangedListener object.

This notification is also triggered when the identity logged into your application changes. For example if the app is working with an unauthenticated user, and your end user later logs in with an identity Amazon Cognito already knows is associated with a different identifier. This means the unique identifier in the Cognito credentials provider object will change:

iOS

// The Cognito iOS SDK uses Notification Center to let your application know
// about a change of identity. The first step is to add your observer
[[NSNotificationCenter defaultCenter] 
  addObserver:self 
  selector:@selector(identityIdDidChange:) 
  name:AWSCognitoIdentityIdChangedNotification object:nil]; 

// This is an example implementation of the selector
-(void)identityDidChange:(NSNotification*)notification {     
  NSDictionary *userInfo = notification.userInfo;     
  NSLog(@"identity changed from %@ to %@", 
    [userInfo objectForKey:AWSCognitoNotificationPreviousId], 
    [userInfo objectForKey:AWSCognitoNotificationNewId]); 

  // your application logic here to handle the identity change.
}

Android

// The Android SDK exposes an IdentityChangedListener interface you can
// implement to receive these notification. Register the listener with 
// the Credentials Provider object
credentialsProvider.registerIdentityChangedListener(
  new CachingCognitoCredentialsProvider.IdentityChangedListener() {
    public void identityChanged(String oldIdentityId, String newIdentityId) {
      // your application logic here to handle the identity change.
    }
  }
);

Initializing other AWS client SDKs

Amazon Cognito also provides temporary, limited-privilege credentials to access your AWS resources. The Cognito credentials provider object can be passed to the constructor for other AWS SDKs directly or set as the default credentials provider for the entire SDK:

iOS

// The first step is to create a configuration object for the AWS SDK
// and initialize it with the Cognito credentials provider
AWSServiceConfiguration *configuration = [AWSServiceConfiguration 
    configurationWithRegion:AWSRegionUSEast1                                                                           
    provider:credentialsProvider];
// We can then set this as the default configuration for all AWS SDKs
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;

Android

// The Android credentials provider object can be passed directly to the 
// constructor for other AWS SDKs.
AmazonDynamoDB client = new AmazonDynamoDBClient(credentialsProvider);

Authenticated users

The Cognito Credentials Provider object exposes a Map property called logins; you can set the authentication tokens you receive from public identity providers in this map to inform Cognito that you are dealing with an authenticated user.

You can set an authentication token at any point during the lifetime of the application. If Cognito recognizes the token as belonging to a different identity than the one currently used on the device it automatically merges the identities together and informs your application through a notification or callback that the identity has changed. If this is a new login previously unknown to Amazon Cognito, the token is automatically associated with the current identity on the device. To force the credentials provider to verify the identity ID and token call the refresh() method of the credentials provider object.

An identity can be associated with logins from different identity providers. You can set an identity for each credentials provider in the logins Map on the credentials provider object.

Your application is in charge of completing the authentication flow with the identity provider. The examples below pick up when the authentication is completed and a valid token is returned by the identity provider. The Amazon Cognito getting started guides for iOS and  Android cover the steps necessary to declare an application with your identity provider.

Facebook

Once the authentication with Facebook is complete the Facebook SDK exposes a populated FBSession object. This needs to be set in the logins property of the Cognito credentials provider:

iOS

NSString *token = FBSession.activeSession.accessTokenData.accessToken; 
// Set the token in the logins map.
credentialsProvider.logins = @{ AWSCognitoLoginProviderKeyFacebook: token };

Android

Map logins = new HashMap();
// Set the facebook token in the logins map
logins.put("graph.facebook.com", Session.getActiveSession().getAccessToken()); 
// Add the new map we created to the Credentials Provider
credentialsProvider.withLogins(logins);

Google

The Google+ documentation takes you through the steps necessary to authenticate an end user with Google. Once the authentication flow is complete you can send the id_token from Google to the Cognito credentials provider:

iOS

// in iOS Google triggers the finishedWithAuth method in your GPPSignInDelegate
// implementation
- (void)finishedWithAuth: (GTMOAuth2Authentication *)auth error: (NSError *) error {     
  NSString *idToken = [auth.parameters objectForKey:@"id_token"];     
  credentialsProvider.logins = @{ AWSCognitoLoginProviderKeyFacebook: idToken };
}

Android

// On Android you can retrieve the Google authentication token from the 
// Google Play Services object
GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
AccountManager am = AccountManager.get(this); 

Account[] accounts = am.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);

// Get the token for the current user
String token = GoogleAuthUtil.getToken(
  getApplicationContext(), 
  accounts[0].name,      
  "audience:server:client_id:YOUR_GOOGLE_CLIENT_ID"); 

// Add it to the map of logins
Map logins = new HashMap(); 
logins.put("accounts.google.com", token); provider.withLogins(logins);

Amazon

Login with Amazon returns an authentication token through its callbacks. The token returned needs to be set in the logins Map once the authentication flow is complete:

iOS

// in iOS Amazon calls the requestDidSucceed method in your 
// AMZNAccessTokenDelegate implementation
- (void)requestDidSucceed:(APIResult *)apiResult {     
  credentialsProvider.logins = @{ AWSCognitoLoginProviderKeyLoginWithAmazon: apiResult.result);
}

Android

// With Android the Login with Amazon flow calls the onSuccess method 
// of the TokenListener interface
@Override 
public void onSuccess(Bundle response) {
  String token = response.getString(AuthzConstants.BUNDLE_KEY.TOKEN.val);     
  Map logins = new HashMap(); 
  // set the Amazon login token    
  logins.put("www.amazon.com", token);          
  credentialsProvider.withLogins(logins); 
}

Amazon Cognito is a simple way to manage your end user identities and securely access your AWS resources. Our getting started guides for the iOS and Android mobile SDKs provide additional details on integrating Amazon Cognito. Also take a look at the API Reference for the iOS and Android SDKs.