Front-End Web & Mobile

Amazon Cognito : Announcing Developer Authenticated Identities

Amazon Cognito helps developers synchronize user-state across devices and securely access AWS resources. When we released Amazon Cognito, we offered the ability to create unique identities through a number of public identity providers (Amazon, Facebook, and Google) and also supported unauthenticated, “guest” users. Based on customer feedback, today we are announcing support for “developer authenticated identities.” With this feature, you’ll be able to use your own authentication system and still utilize Amazon Cognito to synchronize user data and access AWS resources.

Overview

At first, many mobile app users prefer to register a new account with an app rather than connecting their social network profile, such as their Facebook account. Over a period of time, as a sense of trust has been established with the app, users will often move to linking it with their social identity. For this reason, many mobile app developers opt to create their own registration process within their app in addition to supporting social networks such as Login with Amazon, Facebook, or Google.

With the addition of “Developer Authenticated Identities” to Amazon Cognito, developers can use their own authentication system with Cognito. What this means is that your app can benefit from all of the features of Amazon Cognito while utilizing your own authentication system. This works by your app requesting a unique identity ID for your end users based on the identifier you use in your own authentication system. You can use the Cognito identity ID to save and synchronize user data across devices with the Cognito sync service or retrieve temporary, limited-privilege AWS credentials to securely access your AWS resources.

The process is simple, you first request a token for your users by using the server-side Cognito API for developer authenticated identities. Cognito then creates a valid token for your users. You can then exchange this token with Amazon Secure Token Service for AWS credentials.

How do I create a token?

In order to use developer authenticated identities, you use the Amazon Cognito Console to create an identity pool and you configure a developer provider. The developer provider is the “domain” by which Cognito will refer to your users. A new Cognito API called GetOpenIdTokenForDeveloperIdentity generates tokens. You should call this API from your backend using your AWS developer credentials. This API returns a unique Cognito ID for your user and an OpenID Connect token when provided with the Cognito identity pool, developer provider name, and a unique identifier for the end user. You can also provide the user’s token for any of the supported public provider to link the user’s social identity to your backend identity; doing so will link those additional social identities to the Cognito identity for this user. Here is a sample of how to make a server-side call using Java.

Java

AmazonCognitoIdentityClient client = 
  new AmazonCognitoIdentityClient(credentials);
GetOpenIdTokenForDeveloperIdentityRequest tokenRequest = 
  new GetOpenIdTokenForDeveloperIdentityRequest();
tokenRequest.setIdentityPoolId("Identity-Pool-Id");
HashMap<String, String> map = new HashMap<String, String>();

//Key -> Developer Provider Name used when creating the identity pool
//Value -> Unique identifier of the user in your backend
map.put("developerProviderName", "developerUserIdentifier");

//Duration of the generated OpenID Connect Token
tokenRequest.setLogins(map); tokenRequest.setTokenDuration(1000l);

GetOpenIdTokenForDeveloperIdentityResult result 
   = client.getOpenIdTokenForDeveloperIdentity(tokenRequest);
String identityId = result.getIdentityId();
String token = result.getToken();

Implementing your identity provider on the device

To use the developer authenticated features, you will have to call your own backend identity provider from within your mobile app. Both the iOS and Android SDKs have been updated with an additional interface/protocol, AWSCognitoIdentityProvider, which defines what information the credentials provider will expect.  

iOS

// Example (skeleton) identity provider
@interface ExampleIdentityProvider : AWSAbstractIdentityProvider
@property (nonatomic, strong) AWSCognitoIdentity *cib;
@property (nonatomic, strong) NSString *identityPoolId;
@property (nonatomic, strong) NSString *identityId;
@property (nonatomic, strong) NSString *token;
@end

@implementation ExampleIdentityProvider
@synthesize identityPoolId=_identityPoolId;
@synthesize identityId=_identityId;
@synthesize token=_token;

- (BFTask *)getIdentityId {
  // Should ensure that identityId property is valid. The below code can probably
  // be used for most use cases.
  if (self.identityId) {
    return [BFTask taskWithResult:nil];
    } else {
    return [[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
      if (!self.identityId) {
        return [self refresh];
      }
      return nil;
    }];
  }
}

- (BFTask *)refresh {
  // Should ensure that the token property has a valid Cognito openid token from
  // your backend service. Any logins set on the parent credentials provider
  // will be available here as they are passed through.
}
@end

Android

public class ExampleIdentityProvider ExampleProvider extends AWSAbstractCognitoDeveloperIdentityProvider {
  public ExampleIdentityProvider (String acctId, String identityPoolId, Regions region) {
   super(acctId, identityPoolId, region);
  /**
   * Add other necessary objects here, just make sure you have the account id,
   * identityPool id, and region
   */
  }

  @Override
  public String getProviderName() {
  /**
   * Very straightforward, return a string name of the provider.
   * For the standard Cognito backend, it would be: return "Cognito";
   */
   return "Example";
  }

  @Override
  public String refresh() {
  /**
   * Using this call, get an identityId and a valid Cognito openid token from
   * your backend to get a reference to both for the local device.
   * Call update method to make sure the identityId and token are now
   * handy and are utilized appropriately
   */
    update(identityId, token);
    return token;
  }
}

How do I use the token from the device?

You’ll store the OpenID token returned from your backend in the token property of the identity provider, as shown below.

iOS

//Setting the token in the identity provider
self.token = OPEN_ID_TOKEN;
self.identityId = RETURNED_IDENTITY_ID;

Android

//Setting the token in the identity provider
identityProvider.setToken(OPEN_ID_TOKEN);
identityProvider.setIdentityId(RETURNED_IDENTITY_ID);

Once you have implemented your AWSCognitoIdentityProvider to fetch the Cognito OpenID Connect token from your backend you can initialize a Cognito credentials provider to receive temporary, limited-privilege AWS credentials to access your AWS resources.

iOS

AWSCognitoCredentialsProvider *provider = [[AWSCognitoCredentialsProvider alloc]
  initWithRegionType:AWSRegionUSEast1
    identityProvider:MY_PROVIDER
      unauthRoleArn:UNAUTH_ROLE_ARN
        authRoleArn:AUTH_ROLE_ARN];

Android

AWSCognitoIdentityProvider provider 
  = new ExampleBYOIProvider(accountId, identityPoolId);
CognitoCachingCredentialsProvider credentialsProvider
  = new CognitoCachingCredentialsProvider(
    context, provider, unauthRoleArn, authRoleArn);

What happens when they login with Facebook later?

Mobile app users connect their social profiles once they have established a level of trust and comfort with your mobile app. Cognito can help you connect your existing identity, associated with a Cognito ID, to the user’s social identity. To achieve this, you simply have to add the identity provider token to the Logins map in the credentials provider. Once you set the logins map, then you can pass it as a parameter from your backend while making the server-side API call. Our blog post about using the Cognito Credentials Provider goes into more details on how to link social accounts and utilize the AWS temporary credentials.

iOS

// Add the Facebook token for your user to the Logins dictionary.
// If your user is also logged in with Facebook, Google, or Amazon, 
// you can add a new key with the session token.
credentialsProvider.logins = @{
  @(AWSCognitoLoginProviderKeyFacebook):
    FBSession.activeSession.accessTokenData.accessToken
};

Android

// Add the custom token we created for your identity to the Logins map.
// If your user is also logged in with Facebook, Google, or Amazon,
// you can add a new key with the session token.
logins.put("graph.facebook.com", Session.getActiveSession().getAccessToken());

// Add the new map we created to the credentials provider
credentialsProvider.setLogins(logins);

When you link identities this way, Cognito automatically associates the tokens in the background and you can keep working with the same, unique Cognito ID.

Conclusion

Using Amazon Cognito, you can obtain temporary AWS credentials that enable your app to securely sync data across mobile devices. It also enables access to other AWS resources after authenticating your users against your own backend. We are excited to hear how you make use of this feature in your app, so tell us by commenting on this blog post, or reach out to us via the Cognito forum if you have any questions or need additional help.

Useful Links

Cognito Identity API documentation

AWS Java SDK

AWS Ruby SDK

Getting started guide for AWS Android SDK

Getting started guide for AWS iOS SDK