Amazon Cognito is a robust solution for user- and identity-pool management. For java users Amazon provides a more or less simple SDK. In this short article I want to describe how to list all users from an user pool.
The SDK doesn’t provide a listAllUsersAtOnce
functionality out of the box. There is a listUsers
method which is based on pagination. If there are still more users left after a successful listUsers-request, the listUsers-result contains a PaginationToken, that can be used for the next request. The maximum number of users to be returned in one single request is 60.
The listUsers workflow
ListUsersResult result = identityProvider.listUsers(listUsersRequest);
...
while (result.getPaginationToken() != null) {
try {
listUsersRequest.setPaginationToken(result.getPaginationToken());
result = identityProvider.listUsers(listUsersRequest);
...
} catch (TooManyRequestsException e) {
...
}
}
Rate limits
Amazon has defined rate limits for all Cognito API request. The rate limits for Amazon Cognito are describe here [Amazon Cognito rate limits]. If the rate limit is exceeded the API fires a ```TooManyRequestsException``.
Rate limit for all list APIs: 5 per second
Complete code example
My user model
@Data @Builder
public class MyUserModel {
private String id;
private String firstname;
}
The Amazon Cognito connector
@Slf4j
public class AmazonCognitoConnector {
private final static String AWS_ACCESS_KEY = "<YOUR AWS ACCESS KEY>";
private final static String AWS_SECRET_KEY = "<YOUR AWS SECRET KEY>";
private final static String AWS_USER_POOL_ID = "<YOUR USER POOL ID>";
private final static String AWS_REGION = "<YOUR AWS REGION>";
private AWSCognitoIdentityProvider identityProvider;
public AmazonCognitoConnector() {
BasicAWSCredentials creds = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);
AWSCognitoIdentityProviderClientBuilder builder = AWSCognitoIdentityProviderClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(creds));
builder.setRegion(AWS_REGION);
this.identityProvider = builder.build();
}
public List<MyUserModel> listAllUsers(int limit) {
/** check limit 0<limit<=60 "Maximum number of users to be returned" */
if (limit <= 0 || limit > 60) {
throw new IllegalArgumentException("limit must have a value less than or equal to 60");
}
List<MyUserModel> users = new ArrayList<>();
/** prepare Cognito list users request */
ListUsersRequest listUsersRequest = new ListUsersRequest();
listUsersRequest.withUserPoolId(AWS_USER_POOL_ID);
listUsersRequest.setLimit(limit);
/** send list users request */
ListUsersResult result = identityProvider.listUsers(listUsersRequest);
List<UserType> userTypeList = result.getUsers();
users.addAll(userTypeList.stream().map(u -> convertCognitoUser(u)).collect(Collectors.toList()));
/**
* as long as there is a pagination token in the list users result => resend
* list users request with pagination token.
*/
while (result.getPaginationToken() != null) {
try {
listUsersRequest.setPaginationToken(result.getPaginationToken());
result = identityProvider.listUsers(listUsersRequest);
users.addAll(userTypeList.stream().map(u -> convertCognitoUser(u)).collect(Collectors.toList()));
} catch (TooManyRequestsException e) {
/** cognito hard rate limit for "list users": 5 per second. */
try {
log.warn("Too many requests", e);
Thread.sleep(200);
} catch (InterruptedException e1) {
log.warn("Error while sleeping", e);
}
}
}
return users;
}
protected MyUserModel convertCognitoUser(UserType awsCognitoUser) {
MyUserModel.MyUserModelBuilder builder = MyUserModel.builder();
for (AttributeType userAttribute : awsCognitoUser.getAttributes()) {
switch (userAttribute.getName()) {
case "sub":
builder.id(userAttribute.getValue());
break;
case "given_name":
builder.firstname(userAttribute.getValue());
break;
}
}
return builder.build();
}
}
The complete gradle project is here on github.com/elmolm