Requesting AWS Credentials

Now that we’ve successfully connected our app with Google through the Sign-In process, we can use the identity token to create a Cognito identity. To do that, we’re going to use the AWS SDK for JavaScript to create and configure a CognitoIdentityCredentials object. This object will allow our app to get AWS credentials that it can use to directly access Amazon’s web services as an authenticated user. The AWS SDK is already included in the vendor.js file in the prepared workspace.

images/aside-icons/tip.png

If you add other identity providers to this app, you’ll need to follow a similar process for each of them.

To create the CognitoIdentityCredentials for a user, we’ll need an identity token from Google. You should instantiate this object inside the googleSignIn callback you just wrote. Take a look at this, and we’ll walk through it step by step.

 function​ googleSignIn(googleUser) {
 var​ id_token = googleUser.getAuthResponse().id_token;
  AWS.config.update({
  region: ​'us-east-1'​,
  credentials: ​new​ AWS.CognitoIdentityCredentials({
  IdentityPoolId: learnjs.poolId,
  Logins: {
 'accounts.google.com'​: id_token
  }
  })
  })
 }

The first thing you need to do is get the id_token from the response object in googleUser. You need to use this token to create the CognitoIdentityCredentials object. You also need to provide the ID of our identity pool, which you can stash in the namespace object like so:

 var​ learnjs = {
  poolId: ​'us-east-1:aa0e6d15-02da-4304-a819-f316506257e0'
 };

Once you’ve created the credentials, you have to update the AWS configuration to include them, along with the Amazon availability region where our identity pool is located. After the configuration has been updated, you need to apply the changes. Then the Cognito user ID will be available to use. The Cognito ID (not the Google one) is what we want to use to identify our users, and it needs to be included on any user record written to the database. However, before we talk about how to get the Cognito ID, we’ll need to add a little more behavior to the googleSignIn function to accommodate the life cycle of the Google token we just received.

Refreshing Tokens

The token we get from Google is temporary and will expire after one hour. You can see the expiration time for yourself by looking at the expires_in or expires_at property on the object returned by getAuthResponse in the googleSignIn function. After that token expires, Cognito will no longer be able to use it to refresh our AWS credentials.

When that happens, we’ll need to get an updated token. Different identity providers offer different mechanisms for refreshing this token. In Google’s case, we can refresh the token by using the same Google API we loaded to add the Sign-In button. By calling gapi.auth2.getAuthInstance().signIn(), we can update this token, prompting users to reauthorize the app if they’ve signed out.

To trigger this, create a function named refresh. You can define this function inside the googleSignIn function, because you’ll only need it in that scope. You’ll be able to use this function (usually in response to a failed request) to update the identity token and refresh the AWS credentials when they expire.

images/aside-icons/tip.png

Details about the Cognito identity are kept in localStorage.[46]

Inside the refresh function, you can invoke signIn and return the object that the Google API returns. Setting the prompt option to login prevents users from having to needlessly reauthenticate if they’re already signed in. Attaching a then handler lets you update the AWS credentials object when the request returns successfully.

 function​ refresh() {
 return​ gapi.auth2.getAuthInstance().signIn({
  prompt: ​'login'
  }).then(​function​(userUpdate) {
 var​ creds = AWS.config.credentials;
 var​ newToken = userUpdate.getAuthResponse().id_token;
  creds.params.Logins[​'accounts.google.com'​] = newToken;
 return​ learnjs.awsRefresh();
  });
 }

Note how the identity token can be updated without re-creating the credentials object. The last step is to update the AWS credentials, which we can encapsulate in a function named learnjs.awsRefresh. As you’ll see in the next section, the object returned from that function can be used to chain all of these update requests together in an elegant way.

Identity Requests with Deferred Objects and Promises

When you make changes to the AWS.config.credentials[47] object, you need to call the refresh method on that object when you’re done to apply our changes. This function takes a callback that you can use to check if the refresh was successful. The problem is, this refresh process is just one step in a long chain of asynchronous events that you’ll have to coordinate whenever the Google token expires. Unless we want our code to be littered with callbacks inside of callbacks, we need a better way to manage this request.

One way to handle this problem would be to use a Promise. The Promise/A+ standard specifies a type of object that can be used to coordinate asynchronous events and chain them together. Requests can run asynchronously and then be joined when they are both complete. We can also easily pass the result of one request into the next. Any object that meets the standard can interoperate with other implementations. For example, the call to signIn in the refresh function we just looked at returns an object that meets this standard. The problem with Promises is that not all browsers offer their own implementation yet.

Until we have full support for Promises, we can use jQuery Deferred objects. Similar to Promises, jQuery Deferred objects are a way to perform an action whenever an asynchronous action or request is resolved. Deferred objects can exist in one of three states: pending, resolved, or rejected. When we first create the Deferred, it is in the pending state. We can attach callbacks to the Deferred via functions like done, fail, or always. These callbacks will be invoked when the Deferred transitions to the resolved (done) or rejected (fail) states. When a Deferred is resolved, you can provide a value that will be passed to the callback given to the done method. Unlike an event listener, if the Deferred is already resolved or rejected when you attach the callback, it will be invoked immediately.

Joe asks:
Joe asks:
But You Promised?!

Given my preference for web standards, you might be wondering why we’re not using a Promise/A+ compatible object to manage our identity information. Since Promises aren’t available in all browsers yet, I’m falling back to Deferred objects because I know they’ll work, and I’m trying to limit the tools I use in this tutorial.

However, in jQuery 3, Deferred objects will be Promise/A+ compatible. So when that’s released, even if ECMAScript 6 hasn’t made its way into all the browsers yet, we’ll be able to use a web standard to manage these chained requests. Unfortunately, at the time of this writing, jQuery 3 is still in Alpha and not suitable for use in this tutorial.

The first place we can use a Deferred is a new function named learnjs.awsRefresh that we’ll use to apply the AWS config changes. This function can simply wrap up the callback we pass to the refresh function, resolving it if the request succeeds, and rejecting it if the request fails.

 learnjs.awsRefresh = ​function​() {
 var​ deferred = ​new​ $.Deferred();
  AWS.config.credentials.refresh(​function​(err) {
 if​ (err) {
  deferred.reject(err);
  } ​else​ {
  deferred.resolve(AWS.config.credentials.identityId);
  }
  });
 return​ deferred.promise();
 }

In the last section, we invoked this learnjs.awsRefresh from our refresh function inside googleSignIn. We have to refresh the AWS credentials after updating the Google token ID, and chaining all these requests together with Deferred objects and the Promise objects returned by Google’s API makes things a lot easier.

Whenever we use the AWS credentials provided by Cognito, we’ll want to keep this refresh function handy. As we’ll see in the next chapter, being able to refresh these credentials when an error occurs keeps our users from having to take more drastic measures (like reloading the app) when the token times out. Using the returned Promise, we can easily resubmit the request after refreshing the credentials.

The last thing we’ll need to do in the googleSignIn function is apply the AWS configuration we created when we initially received the Google token. Once we do that, we can create an identity object that will hide all these vendor-specific identity management details from the rest of our application.

Creating an Identity Deferred

To manage the identity in our app, we’re going to use another Deferred object. This lets a view or any other part of our app take action when users log in, and safely access the profile information to perform those actions. We can create the identity Deferred in the namespace of our application like so:

 learnjs.identity = ​new​ $.Deferred();

The last step in the googleSignIn function will be to call learnjs.awsRefresh and resolve this Deferred. Any views or other parts of our app that want to perform actions when users log in will be able to do so by attaching a done handler to the Deferred. You can resolve this Deferred with an object that will provide access to the Cognito ID, the refresh function, and other profile information, such as a user’s email address.

 learnjs.awsRefresh().then(​function​(id) {
  learnjs.identity.resolve({
  id: id,
  email: googleUser.getBasicProfile().getEmail(),
  refresh: refresh
  });
 });

Because this information is available through an identity Promise, we can call it without depending on any specific identity provider. So whether users log in with Google, Facebook, or another service, the rest of our app will never need to know the difference. No matter what identity providers you use, the structure of the object resolved in this Deferred can always be the same.

Now that we’ve created a Cognito identity for our users, let’s do something with it. We’re going to create a profile view that users can use to see how they’re connected to our app. Not only will this be a useful view, but it will give us a way to see our new identity management at work.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.1.220