aws, learning, Amazon Cognito [part1]

Ngoc Phan
5 min readJul 18, 2021

--

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

Developer Authenticated Identities Authflow

Developer Authenticated Identities Authflow

Basic Authflow

As covered in previous blog posts, a user authenticating through Cognito will go through a three-step process to bootstrap their credentials:

  1. GetId — Create (or retrieve) a Cognito identity. Only necessary once per device.
  2. GetOpenIdToken — Obtain an OpenId Connect token for that identity.
  3. AssumeRoleWithWebIdentity — Exchange token for AWS credentials scoped to the identity.

Which Authflow Should I Use?

For most customers, the Enhanced Flow is the correct choice, as it offers many benefits over the Basic Flow:

  • One fewer network call to get credentials on the device.
  • All calls are made to Amazon Cognito, meaning it is also one less network connection.
  • Roles no longer need to be embedded in your application, only an identity pool id and region are necessary to start bootstrapping credentials.

API

With developer authenticated identities, we introduced a new API, GetOpenIdTokenForDeveloperIdentity. This API call replaces the use of GetId and GetOpenIdToken from the device and should be called from your backend as part of your own authentication API.

With this change, the authflow from the device becomes:

  1. Your authentication API (which calls GetOpenIdTokenForDeveloperIdentity)
  2. AssumeRoleWithWebIdentity

The AWS Mobile SDK has been updated to support this flow via the use of a new interface called AWSCognitoIdentityProvider. See the Developer Guides (iOS|Android) for information on implementing these providers.

GetOpenIdTokenForDeveloperIdentity

As mentioned earlier, GetOpenIdTokenForDeveloperIdentity replaces the use of GetId and GetOpenIdToken from the device. Because this API call is signed by your AWS credentials, Cognito can trust that the user identifier supplied in the API call is valid. This replaces the token validation Cognito performs with public providers.

The API takes a number of fields, but only two are required:

  • IdentityPoolId — The Id of the pool you are using.
  • Logins — A map of logins for this identity. As with GetId and GetOpenIdToken, you can supply any supported public provider token, but you can additionally supply a user identifier keyed by the developer provider name that you set when you created the identity pool. This should be a unique identifer for this user in your system.
"Logins": {
"graph.facebook.com": "FB_TOKEN",
"accounts.google.com": "GOOGLE_TOKEN",
"www.amazon.com": "AMZN_TOKEN",
"login.mycompany.myapp": "USER_IDENTIFIER"
}

If the user identifier isn’t already linked to an existing identity, Cognito will create a new identity and return the new identity id and an OpenId Connect token for that identity. If the user identifer is already linked, Cognito will return the pre-existing identity id and an OpenId Connect token.

Ref: https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-2-developer-authenticated-identities/

GetId

The GetId API call is the first call necessary to establish a new identity in Cognito.

Unauthenticated Access

One of Cognito’s best features is the ability to allow unauthenticated “guest” access in your applications. If this feature is enabled in your identity pool, users can request a new identity ID at any time via the GetId API. The application is expected to cache this identity ID to make subsequent calls to Cognito (the AWS SDK for iOS, AWS SDK for Android, and AWS SDK for JavaScript in the Browser all have credentials providers that handle this caching for you).

Authenticated Access

When you’ve configured your application with support for a public login provider (Facebook, Google+, Login with Amazon), users will also be able to supply tokens (OAuth or OpenID Connect) that identify them in those providers. When used in a call to GetId, Cognito will either create a new authenticated identity or return the identity already associated with that particular login. Cognito does this by validating the token with the provider and ensuring that:

  1. The token is valid and from the configured provider.
  2. The token is not expired.
  3. The token matches the application identifier created with that provider (e.g., Facebook app ID).
  4. The token matches the user identifier.

GetOpenIdToken

The GetOpenIdToken API call is called after we have an established identity ID. If we have a cached identity ID, this can be the first call we make during an app session.

Unauthenticated Access

If we have an unathenticated identity, all that is necessary to get a token for that identity is the identity ID itself. If the ID is authenticated (or disabled), it is not possible to get an unauthenticated token for that identity.

Authenticated Access

If we have an authenticated identity, we must pass at least one valid token for a login already associated with that identity. All tokens passed in during the GetOpenIdToken call must pass the same validation mentioned earlier; if any fail, the whole call fails. The response from the GetOpenIdToken call also includes the identity ID. This is because, in the authenticated case, the identity ID you pass in may not be the one that is returned.

AssumeRoleWithWebIdentity

This policy defines that we want to allow federated users from cognito-identity.amazonaws.com (the issuer of the OpenID Connect token) to assume this role. Additionally, we make the restriction that the aud of the token, in our case the identity pool ID, matches our identity pool. Finally, we specify that the amr of the token contains the value unauthenticated.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:12345678-dead-beef-cafe-123456790ab"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "unauthenticated"
}
}
}
]
}

You can create a role that trusts only users that logged in via Facebook, simply by changing the amr clause to look like the following:

"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "graph.facebook.com"
}

Ref: https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication/

Implement an Identity Provider for Android

public class DeveloperAuthenticationProvider extends AWSAbstractCognitoDeveloperIdentityProvider {  private static final String developerProvider = "<Developer_provider_name>";  public DeveloperAuthenticationProvider(String accountId, String identityPoolId, Regions region) {
super(accountId, identityPoolId, region);
// Initialize any other objects needed here.
}
// Return the developer provider name which you choose while setting up the
// identity pool in the &COG; Console
@Override
public String getProviderName() {
return developerProvider;
}
// Use the refresh method to communicate with your backend to get an
// identityId and token.
@Override
public String refresh() {
// Override the existing token
setToken(null);
// Get the identityId and token by making a call to your backend
// (Call to your backend)
// Call the update method with updated identityId and token to make sure
// these are ready to be used from Credentials Provider.
update(identityId, token);
return token;
} // If the app has a valid identityId return it, otherwise get a valid
// identityId from your backend.
@Override
public String getIdentityId() {
// Load the identityId from the cache
identityId = cachedIdentityId;
if (identityId == null) {
// Call to your backend
} else {
return identityId;
}
}
}

--

--

Ngoc Phan
Ngoc Phan

Written by Ngoc Phan

Web developer, interesting technology

No responses yet