Unofficial Amazon Cognito Identity SDK written in Dart for Dart.
Dart Packages: https://pub.dev/packages/amazon_cognito_identity_dart_2
Based on amazon-cognito-identity-js. First version was created by Jonsaw amazon-cognito-identity-dart.
Need ideas to get started?
- Check out use cases below.
- Example Flutter app can be found here.
- Authenticated access to:
- Follow the tutorial on Serverless Stack for best Cognito setup.
Note: When creating the App, the generate client secret box must be unchecked.
Please note that this package is not production ready.
Use Case 1. Registering a user with the application. One needs to create a CognitoUserPool object by providing a UserPoolId and a ClientId and signing up by using a username, password, attribute list, and validation data.
import 'package:amazon_cognito_identity_dart/cognito.dart';
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final userAttributes = [
new AttributeArg(name: 'first_name', value: 'Jimmy'),
new AttributeArg(name: 'last_name', value: 'Wong'),
];
var data;
try {
data = await userPool.signUp(
'[email protected]',
'Password001',
userAttributes: userAttributes,
);
} catch (e) {
print(e);
}
Use case 2. Confirming a registered, unauthenticated user using a confirmation code received via SMS/email.
import 'package:amazon_cognito_identity_dart/cognito.dart';
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final cognitoUser = new CognitoUser('[email protected]', userPool);
bool registrationConfirmed = false;
try {
registrationConfirmed = await cognitoUser.confirmRegistration('123456');
} catch (e) {
print(e);
}
print(registrationConfirmed);
Use case 3. Resending a confirmation code via SMS/email for confirming registration for unauthenticated users.
import 'package:amazon_cognito_identity_dart/cognito.dart';
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final cognitoUser = new CognitoUser('[email protected]', userPool);
final String status;
try {
status = await cognitoUser.resendConfirmationCode();
} catch (e) {
print(e);
}
Use case 4. Authenticating a user and establishing a user session with the Amazon Cognito Identity service.
import 'package:amazon_cognito_identity_dart/cognito.dart';
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final cognitoUser = new CognitoUser('[email protected]', userPool);
final authDetails = new AuthenticationDetails(
username: '[email protected]',
password: 'Password001',
);
CognitoUserSession session;
try {
session = await cognitoUser.authenticateUser(authDetails);
} on CognitoUserNewPasswordRequiredException catch (e) {
// handle New Password challenge
} on CognitoUserMfaRequiredException catch (e) {
// handle SMS_MFA challenge
} on CognitoUserSelectMfaTypeException catch (e) {
// handle SELECT_MFA_TYPE challenge
} on CognitoUserMfaSetupException catch (e) {
// handle MFA_SETUP challenge
} on CognitoUserTotpRequiredException catch (e) {
// handle SOFTWARE_TOKEN_MFA challenge
} on CognitoUserCustomChallengeException catch (e) {
// handle CUSTOM_CHALLENGE challenge
} on CognitoUserConfirmationNecessaryException catch (e) {
// handle User Confirmation Necessary
} on CognitoClientException catch (e) {
// handle Wrong Username and Password and Cognito Client
}catch (e) {
print(e);
}
print(session.getAccessToken().getJwtToken());
Use case 5. Retrieve user attributes for authenticated users.
List<CognitoUserAttribute> attributes;
try {
attributes = await cognitoUser.getUserAttributes();
} catch (e) {
print(e);
}
attributes.forEach((attribute) {
print('attribute ${attribute.getName()} has value ${attribute.getValue()}');
});
Use case 6. Verify user attribute for an authenticated user.
var data;
try {
data = await cognitoUser.getAttributeVerificationCode('email');
} catch {
print(e);
}
print(data);
// obtain verification code...
bool attributeVerified = false;
try {
attributeVerified = await cognitoUser.verifyAttribute('email', '123456');
} catch (e) {
print(e);
}
print(attributeVerified);
Use case 7. Delete user attributes for authenticated users.
try {
final List<String> attributeList = ['nickname'];
cognitoUser.deleteAttributes(attributeList);
} catch (e) {
print(e);
}
Use case 8. Update user attributes for authenticated users.
final List<CognitoUserAttribute> attributes = [];
attributes.add(new CognitoUserAttribute(name: 'nickname', value: 'joe'));
try {
await cognitoUser.updateAttributes(attributes);
} catch (e) {
print(e);
}
Use case 9. Enabling MFA for a user on a pool that has an optional MFA setting for authenticated users.
bool mfaEnabled = false;
try {
mfaEnabled = await cognitoUser.enableMfa();
} catch (e) {
print(e);
}
print(mfaEnabled);
Use case 10. Disabling MFA for a user on a pool that has an optional MFA setting for authenticated users.
bool mfaDisabled = false;
try {
mfaDisabled = await cognitoUser.disableMfa();
} catch (e) {
print(e);
}
print(mfaDisabled);
Use case 11. Changing the current password for authenticated users.
bool passwordChanged = false;
try {
passwordChanged = await cognitoUser.changePassword(
'oldPassword',
'newPassword',
);
} catch (e) {
print(e);
}
print(passwordChanged);
Use case 12. Starting and completing a forgot password flow for an unauthenticated user.
import 'package:amazon_cognito_identity_dart/cognito.dart';
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final cognitoUser = new CognitoUser('[email protected]', userPool);
var data;
try {
data = await cognitoUser.forgotPassword();
} catch (e) {
print(e);
}
print('Code sent to $data');
// prompt user for verification input...
bool passwordConfirmed = false;
try {
passwordConfirmed = await cognitoUser.confirmPassword(
'123456', 'newPassword');
} catch (e) {
print(e);
}
print(passwordConfirmed);
Use case 13. Deleting authenticated users.
bool userDeleted = false
try {
userDeleted = await cognitoUser.deleteUser();
} catch (e) {
print(e);
}
print(userDeleted);
Use case 14. Signing out from the application.
await cognitoUser.signOut();
Use case 15. Global signout for authenticated users (invalidates all issued tokens).
await cognitoUser.globalSignOut();
Use case 16. Manually set key value pairs that can be passed to Cognito Lambda Triggers.
Map<String, String> validationData = {
'myCustomKey1': 'myCustomValue1',
'myCustomKey2': 'myCustomValue2',
};
Use case 17. Manually set Authorization header (e.g. JWT token)
signedRequest = new SigV4Request(
awsSigV4Client,
method: Method.post,
authorizationHeader: session.idToken.jwtToken, // <---- custom authorizationHeader
path: '/path',
headers: new Map<String, String>.from({
CONTENT_TYPE: APPLICATION_GRAPHQL,
ACCEPT: APPLICATION_JSON,
}),
body: new Map<String, String>.from(
{
QUERY: query,
},
),
);
Use case 18. Resetting an user password after first user authentication (when an account has status FORCE_CHANGE_PASSWORD). When an administrator creates the user pool account then an user has to change its password after first sign-in. Moreover the Cognito User Pool service can send a list of required attributes that user has to set when settings a new password.
import 'package:amazon_cognito_identity_dart_2/cognito.dart';
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx'
);
final cognitoUser = new CognitoUser('[email protected]', userPool);
final authDetails = new AuthenticationDetails(
username: '[email protected]',
password: 'Password001!',
);
CognitoUserSession session;
try {
session = await cognitoUser.authenticateUser(authDetails);
} on CognitoUserNewPasswordRequiredException catch (e) {
try {
if(e.requiredAttributes.isEmpty) {
// No attribute hast to be set
session = await cognitoUser.sendNewPasswordRequiredAnswer("NewPassword002!");
} else {
// All attributes from the e.requiredAttributes has to be set.
print(e.requiredAttributes);
// For example obtain and set the name attribute.
var attributes = { "name": "Adam Kaminski"};
session = await cognitoUser.sendNewPasswordRequiredAnswer("NewPassword002!", attributes);
}
} on CognitoUserMfaRequiredException catch (e) {
// handle SMS_MFA challenge
} on CognitoUserSelectMfaTypeException catch (e) {
// handle SELECT_MFA_TYPE challenge
} on CognitoUserMfaSetupException catch (e) {
// handle MFA_SETUP challenge
} on CognitoUserTotpRequiredException catch (e) {
// handle SOFTWARE_TOKEN_MFA challenge
} on CognitoUserCustomChallengeException catch (e) {
// handle CUSTOM_CHALLENGE challenge
} catch (e) {
print(e);
}
} on CognitoUserMfaRequiredException catch (e) {
// handle SMS_MFA challenge
} on CognitoUserSelectMfaTypeException catch (e) {
// handle SELECT_MFA_TYPE challenge
} on CognitoUserMfaSetupException catch (e) {
// handle MFA_SETUP challenge
} on CognitoUserTotpRequiredException catch (e) {
// handle SOFTWARE_TOKEN_MFA challenge
} on CognitoUserCustomChallengeException catch (e) {
// handle CUSTOM_CHALLENGE challenge
} on CognitoUserConfirmationNecessaryException catch (e) {
// handle User Confirmation Necessary
} catch (e) {
print(e);
}
print(session.getAccessToken().getJwtToken());
Get a authenticated user's AWS Credentials. Use with other signing processes like Signature Version 4.
import 'package:amazon_cognito_identity_dart/cognito.dart';
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final cognitoUser = new CognitoUser('[email protected]', userPool);
final authDetails = new AuthenticationDetails(
username: '[email protected]',
password: 'Password001',
);
final session = await cognitoUser.authenticateUser(authDetails);
final credentials = new CognitoCredentials(
'ap-southeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', userPool);
await credentials.getAwsCredentials(session.getIdToken().getJwtToken());
print(credentials.accessKeyId);
print(credentials.secretAccessKey);
print(credentials.sessionToken);
S3 Uploads using HTTP Presigned Post.
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:async/async.dart';
import 'package:http/http.dart' as http;
import 'package:amazon_cognito_identity_dart/cognito.dart';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';
class Policy {
String expiration;
String region;
String bucket;
String key;
String credential;
String datetime;
String sessionToken;
int maxFileSize;
Policy(
this.key,
this.bucket,
this.datetime,
this.expiration,
this.credential,
this.maxFileSize,
this.sessionToken,
{this.region = 'us-east-1'},
);
factory Policy.fromS3PresignedPost(
String key,
String bucket,
int expiryMinutes,
String accessKeyId,
int maxFileSize,
String sessionToken,
{String region},
) {
final datetime = SigV4.generateDatetime();
final expiration = (DateTime.now())
.add(Duration(minutes: expiryMinutes))
.toUtc()
.toString()
.split(' ')
.join('T');
final cred =
'$accessKeyId/${SigV4.buildCredentialScope(datetime, region, 's3')}';
final p = Policy(
key, bucket, datetime, expiration, cred, maxFileSize, sessionToken,
region: region);
return p;
}
String encode() {
final bytes = utf8.encode(toString());
return base64.encode(bytes);
}
@override
String toString() {
return '''
{ "expiration": "${this.expiration}",
"conditions": [
{"bucket": "${this.bucket}"},
["starts-with", "\$key", "${this.key}"],
{"acl": "public-read"},
["content-length-range", 1, ${this.maxFileSize}],
{"x-amz-credential": "${this.credential}"},
{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
{"x-amz-date": "${this.datetime}" },
{"x-amz-security-token": "${this.sessionToken}" }
]
}
''';
}
}
void main() async {
const _awsUserPoolId = 'ap-southeast-xxxxxxxxxxx';
const _awsClientId = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
const _identityPoolId = 'ap-southeast-1:xxxxxxxxx-xxxx-xxxx-xxxxxxxxxxx';
final _userPool = CognitoUserPool(_awsUserPoolId, _awsClientId);
final _cognitoUser = CognitoUser('+60100000000', _userPool);
final authDetails =
AuthenticationDetails(username: '+60100000000', password: 'p&ssW0RD');
CognitoUserSession _session;
try {
_session = await _cognitoUser.authenticateUser(authDetails);
} catch (e) {
print(e);
}
final _credentials = CognitoCredentials(_identityPoolId, _userPool);
await _credentials.getAwsCredentials(_session.getIdToken().getJwtToken());
const _region = 'ap-southeast-1';
const _s3Endpoint = 'https://my-s3-bucket.s3-ap-southeast-1.amazonaws.com';
final file = File(path.join('/path/to/my/folder', 'square-cinnamon.jpg'));
final stream = http.ByteStream(DelegatingStream.typed(file.openRead()));
final length = await file.length();
final uri = Uri.parse(_s3Endpoint);
final req = http.MultipartRequest("POST", uri);
final multipartFile = http.MultipartFile('file', stream, length,
filename: path.basename(file.path));
final policy = Policy.fromS3PresignedPost(
'test/square-cinnamon.jpg',
'my-s3-bucket',
15,
_credentials.accessKeyId,
length,
_credentials.sessionToken,
region: _region);
final key = SigV4.calculateSigningKey(
_credentials.secretAccessKey, policy.datetime, _region, 's3');
final signature = SigV4.calculateSignature(key, policy.encode());
req.files.add(multipartFile);
req.fields['key'] = policy.key;
req.fields['acl'] = 'public-read';
req.fields['X-Amz-Credential'] = policy.credential;
req.fields['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256';
req.fields['X-Amz-Date'] = policy.datetime;
req.fields['Policy'] = policy.encode();
req.fields['X-Amz-Signature'] = signature;
req.fields['x-amz-security-token'] = _credentials.sessionToken;
try {
final res = await req.send();
await for (var value in res.stream.transform(utf8.decoder)) {
print(value);
}
} catch (e) {
print(e.toString());
}
}
Signing S3 GET Object using Authorization
header.
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:amazon_cognito_identity_dart/cognito.dart';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';
import 'package:http/http.dart' as http;
void main() {
const _awsUserPoolId = 'ap-southeast-1_xxxxxxxx';
const _awsClientId = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
const _identityPoolId =
'ap-southeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
final _userPool = CognitoUserPool(_awsUserPoolId, _awsClientId);
final _cognitoUser = CognitoUser('+60100000000', _userPool);
final authDetails =
AuthenticationDetails(username: '+60100000000', password: 'p@ssW0rd');
CognitoUserSession _session;
try {
_session = await _cognitoUser.authenticateUser(authDetails);
} catch (e) {
print(e);
return;
}
final _credentials = CognitoCredentials(_identityPoolId, _userPool);
await _credentials.getAwsCredentials(_session.getIdToken().getJwtToken());
final host = 's3.ap-southeast-1.amazonaws.com';
final region = 'ap-southeast-1';
final service = 's3';
final key =
'my-s3-bucket/ap-southeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/square-cinnamon.jpg';
final payload = SigV4.hashCanonicalRequest('');
final datetime = SigV4.generateDatetime();
final canonicalRequest = '''GET
${'/$key'.split('/').map((s) => Uri.encodeComponent(s)).join('/')}
host:$host
x-amz-content-sha256:$payload
x-amz-date:$datetime
x-amz-security-token:${_credentials.sessionToken}
host;x-amz-content-sha256;x-amz-date;x-amz-security-token
$payload''';
final credentialScope =
SigV4.buildCredentialScope(datetime, region, service);
final stringToSign = SigV4.buildStringToSign(datetime, credentialScope,
SigV4.hashCanonicalRequest(canonicalRequest));
final signingKey = SigV4.calculateSigningKey(
_credentials.secretAccessKey, datetime, region, service);
final signature = SigV4.calculateSignature(signingKey, stringToSign);
final authorization = [
'AWS4-HMAC-SHA256 Credential=${_credentials.accessKeyId}/$credentialScope',
'SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token',
'Signature=$signature',
].join(',');
final uri = Uri.https(host, key);
http.Response response;
try {
response = await http.get(uri, headers: {
'Authorization': authorization,
'x-amz-content-sha256': payload,
'x-amz-date': datetime,
'x-amz-security-token': _credentials.sessionToken,
});
} catch (e) {
print(e);
return;
}
final file = File(path.join(
'/path/to/my/folder',
'square-cinnamon-downloaded.jpg'));
try {
await file.writeAsBytes(response.bodyBytes);
} catch (e) {
print(e.toString());
return;
}
print('complete!');
}
Authenticating Amazon Cognito User Pool using JWT Tokens.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:amazon_cognito_identity_dart/cognito.dart';
void main() async {
const _awsUserPoolId = 'ap-southeast-1_xxxxxxxxx';
const _awsClientId = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';
const _identityPoolId = 'ap-southeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
final _userPool = CognitoUserPool(_awsUserPoolId, _awsClientId);
final _cognitoUser = CognitoUser('+60100000000', _userPool);
final authDetails =
AuthenticationDetails(username: '+60100000000', password: 'p@ssW0rd');
CognitoUserSession _session;
try {
_session = await _cognitoUser.authenticateUser(authDetails);
} catch (e) {
print(e);
return;
}
final _credentials = CognitoCredentials(_identityPoolId, _userPool);
await _credentials.getAwsCredentials(_session.getIdToken().getJwtToken());
final _endpoint =
'https://xxxxxxxxxxxxxxxxxxxxxxxxxx.appsync-api.ap-southeast-1.amazonaws.com';
final body = {
'operationName': 'CreateItem',
'query': '''mutation CreateItem {
createItem(name: "Some Name") {
name
}
}''',
};
http.Response response;
try {
response = await http.post(
'$_endpoint/graphql',
headers: {
'Authorization': _session.getAccessToken().getJwtToken(),
'Content-Type': 'application/json',
},
body: json.encode(body),
);
} catch (e) {
print(e);
}
print(response.body);
}
Signing GraphQL requests for authenticated users with IAM Authorization type for access to AppSync data.
import 'package:http/http.dart' as http;
import 'package:amazon_cognito_identity_dart/cognito.dart';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';
void main() async {
final credentials = new CognitoCredentials(
'ap-southeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', userPool);
await credentials.getAwsCredentials(session.getIdToken().getJwtToken());
const endpoint =
'https://xxxxxxxxxxxxxxxxxxxxxxxxxx.appsync-api.ap-southeast-1.amazonaws.com';
final awsSigV4Client = new AwsSigV4Client(
credentials.accessKeyId, credentials.secretAccessKey, endpoint,
serviceName: 'appsync',
sessionToken: credentials.sessionToken,
region: 'ap-southeast-1');
final String query = '''query GetEvent {
getEvent(id: "3dcd52c3-1fd6-4e4d-8da6-946ef4a0c94d") {
id
name
comments(limit: 10) {
items {
content
createdAt
}
}
}
}''';
final signedRequest = new SigV4Request(awsSigV4Client,
method: 'POST', path: '/graphql',
headers: new Map<String, String>.from(
{'Content-Type': 'application/graphql; charset=utf-8'}),
body: new Map<String, String>.from({
'operationName': 'GetEvent',
'query': query}));
http.Response response;
try {
response = await http.post(
signedRequest.url,
headers: signedRequest.headers, body: signedRequest.body);
} catch (e) {
print(e);
}
print(response.body);
}
Signing requests for authenticated users for access to secured routes to API Gateway and Lambda.
import 'package:http/http.dart' as http;
import 'package:amazon_cognito_identity_dart/cognito.dart';
import 'package:amazon_cognito_identity_dart/sig_v4.dart';
void main() async {
final credentials = new CognitoCredentials(
'ap-southeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', userPool);
await credentials.getAwsCredentials(session.getIdToken().getJwtToken());
const endpoint =
'https://xxxx.execute-api.ap-southeast-1.amazonaws.com/dev';
final awsSigV4Client = new AwsSigV4Client(
credentials.accessKeyId, credentials.secretAccessKey, endpoint,
sessionToken: credentials.sessionToken,
region: 'ap-southeast-1');
final signedRequest = new SigV4Request(awsSigV4Client,
method: 'POST',
path: '/projects',
headers: new Map<String, String>.from(
{'header-1': 'one', 'header-2': 'two'}),
queryParams: new Map<String, String>.from({'tracking': 'x123'}),
body: new Map<String, dynamic>.from({'color': 'blue'}));
http.Response response;
try {
response = await http.post(
signedRequest.url,
headers: signedRequest.headers,
body: signedRequest.body,
);
} catch (e) {
print(e);
}
print(response.body);
}
Persist user session using custom storage.
Shared Preferences Plugin storage example found here.
import 'dart:convert';
import 'package:amazon_cognito_identity_dart/cognito.dart';
Map<String, String> _storage = {};
class CustomStorage extends CognitoStorage {
String prefix;
CustomStorage(this.prefix);
@override
Future setItem(String key, value) async {
_storage[prefix+key] = json.encode(value);
return _storage[prefix+key];
}
@override
Future getItem(String key) async {
if (_storage[prefix+key] != null) {
return json.decode(_storage[prefix+key]);
}
return null;
}
@override
Future removeItem(String key) async {
return _storage.remove(prefix+key);
}
@override
Future<void> clear() async {
_storage = {};
}
}
final customStore = new CustomStorage('custom:');
final userPool = new CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
storage: customStore,
);
final cognitoUser = new CognitoUser(
'[email protected]', userPool, storage: customStore);
final authDetails = new AuthenticationDetails(
username: '[email protected]', password: 'Password001');
await cognitoUser.authenticateUser(authDetails);
// some time later...
final user = await userPool.getCurrentUser();
final session = await user.getSession();
print(session.isValid());
CognitoCredentials _credential = new CognitoCredentials('ap-southeast-1_xxxxxxxxx', userPool);
await _credential.getAwsCredentials(accessToken, 'graph.facebook.com')
print(_credential.sessionToken);