Unofficial Amazon Cognito Identity Provider Dart SDK, to add user sign-up / sign-in to your mobile and web apps with AWS Cloud Services. Based on amazon-cognito-identity-dart
Package selection guidance compiled from public package information, community data, and project usage.
A Dart SDK for integrating Amazon Cognito Identity Provider into Flutter apps, enabling user sign-up, sign-in, and authentication with AWS Cloud Services. Built as an unofficial fork of the original amazon-cognito-identity-dart, it supports multiple platforms including Android, iOS, Web, macOS, Windows, and Linux. The package simplifies secure user management by leveraging AWS's scalable identity infrastructure, ideal for developers building cross-platform applications requiring robust authentication.
Use cases
User registration and login
Secure access to AWS resources
Cross-platform app authentication
Customizable sign-in flows
Integration with AWS Amplify
Session management
Key features
Supports user pools and identity pools
Cross-platform compatibility
JWT token handling
Passwordless sign-in options
Refresh token support
Event-driven authentication lifecycle
Suitable for
Flutter developers using AWS
Apps needing scalable user auth
Projects requiring AWS integration
Mobile and web applications
Teams adopting serverless architectures
Considerations
Unofficial SDK – no official AWS support
Requires manual configuration of AWS resources
Limited documentation compared to official tools
Depends on external AWS service availability
Not suitable for enterprise-grade compliance without review
Original README
Original README snapshot from the linked source repository. Visit the repository for the latest content.
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_2/cognito.dart';
final userPool = CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final userAttributes = [
AttributeArg(name: 'first_name', value: 'Jimmy'),
AttributeArg(name: 'last_name', value: 'Wong'),
];
var data;
try {
data = await userPool.signUp(
'email@inspire.my',
'Password001',
userAttributes: userAttributes,
);
} catch (e) {
print(e);
}
Use case 2. Confirming a registered, unauthenticated user using a confirmation code received via SMS/email.
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.
Use case 19. Using this library with Cognito's federated sign in on mobile devices.
Use flutter_webview (https://pub.dev/packages/webview_flutter) to navigate to Cognito's authorize URL.
Use flutter_webview's navigationDelegate to catch the redirect to myapp://?code=<AUTH_CODE>.
Make a POST request to Cognito's token URL to get your tokens.
Create the session and user with the tokens.
finalCompleter<WebViewController> _webViewController = Completer<WebViewController>();
WidgetgetWebView() {
var url = "https://${COGNITO_POOL_URL}" +
".amazoncognito.com/oauth2/authorize?identity_provider=Google&redirect_uri=" +
"myapp://&response_type=CODE&client_id=${COGNITO_CLIENT_ID}" +
"&scope=email%20openid%20profile%20aws.cognito.signin.user.admin";
returnWebView(
initialUrl: url,
userAgent: 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) ' +
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Mobile Safari/537.36',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_webViewController.complete(webViewController);
},
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith("myapp://?code=")) {
String code = request.url.substring("myapp://?code=".length);
signUserInWithAuthCode(code);
returnNavigationDecision.prevent;
}
returnNavigationDecision.navigate;
},
gestureNavigationEnabled: true,
);
}
final userPool = CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx'
);
staticFuturesignUserInWithAuthCode(String authCode) async {
String url = "https://${COGNITO_POOL_URL}" +
".amazoncognito.com/oauth2/token?grant_type=authorization_code&client_id=" +
"${COGNITO_CLIENT_ID}&code=" + authCode + "&redirect_uri=myapp://";
final response = await http.post(url, body: {}, headers: {'Content-Type': 'application/x-www-form-urlencoded'});
if (response.statusCode != 200) {
throwException("Received bad status code from Cognito for auth code:" +
response.statusCode.toString() + "; body: " + response.body);
}
final tokenData = json.decode(response.body);
final idToken = CognitoIdToken(tokenData['id_token']);
final accessToken = CognitoAccessToken(tokenData['access_token']);
final refreshToken = CognitoRefreshToken(tokenData['refresh_token']);
final session = CognitoUserSession(idToken, accessToken, refreshToken: refreshToken);
final user = CognitoUser(null, userPool, signInUserSession: session);
// NOTE: in order to get the email from the list of user attributes, make sure you select email in the list of// attributes in Cognito and map it to the email field in the identity provider.final attributes = await user.getUserAttributes();
for (CognitoUserAttribute attribute in attributes) {
if (attribute.getName() == "email") {
user.username = attribute.getValue();
break;
}
}
return user;
}
}
Addtional Features
Get AWS Credentials
Get a authenticated user's AWS Credentials. Use with other signing processes like Signature Version 4.
import'package:amazon_cognito_identity_dart_2/cognito.dart';
final userPool = CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
);
final cognitoUser = CognitoUser('email@inspire.my', userPool);
final authDetails = AuthenticationDetails(
username: 'email@inspire.my',
password: 'Password001',
);
final session = await cognitoUser.authenticateUser(authDetails);
final credentials = 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);
Signing Requests
For S3 Uploads
S3 Upload to user "folder" 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_2/cognito.dart';
import'package:amazon_cognito_identity_dart_2/sig_v4.dart';
classPolicy{
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',
});
factoryPolicy.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;
}
Stringencode() {
final bytes = utf8.encode(toString());
return base64.encode(bytes);
}
@overrideStringtoString() {
// Safe to remove the "acl" line if your bucket has no ACL permissionsreturn'''
{ "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}" }
]
}
''';
}
}
voidmain() 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));
finalString fileName = 'square-cinnamon.jpg';
finalString usrIdentityId = _credentials.userIdentityId;
finalString bucketKey = 'test/$usrIdentityId/$fileName';
final policy = Policy.fromS3PresignedPost(
bucketKey,
'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'; // Safe to remove this if your bucket has no ACL permissions
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();
awaitfor (var value in res.stream.transform(utf8.decoder)) {
print(value);
}
} catch (e) {
print(e.toString());
}
}
The role attached to the identity pool (e.g. the ..._poolAuth role) should contain a policy like this:
By default you can refresh access and ID tokens with refreshSession(CognitoRefreshToken(...)), which uses Cognito InitiateAuth with REFRESH_TOKEN_AUTH.
If your app client has refresh token rotation enabled, use getTokensFromRefreshToken instead. That calls the GetTokensFromRefreshToken API so Cognito can return a new refresh token when it rotates; refreshSession does not surface rotated refresh tokens in that setup.
Reuse of an invalidated refresh token (for example after rotation) may yield CognitoClientException with code RefreshTokenReuseException — treat it as requiring a new sign-in.
The original amazon-cognito-identity-js which this library is based off, doesn't support client secret. This feature has been added since version 0.1.9, to use it, simply set your client secret when creating CognitoUserPool:
final userPool = CognitoUserPool(
'ap-southeast-1_xxxxxxxxx',
'xxxxxxxxxxxxxxxxxxxxxxxxxx',
clientSecret: 'xxxxxxxxxxxxxxxxxxxxxxx'
);
Flutter web sign-in performance
To improve performance of modPow() used in authenticateUser(), use an external JavaScript call to do the modPow calculation using the native BigInt type.
Include the following JavaScript method in your top level index.html page for your flutter web app.
Also, add package:js as a dependency in your app's pubspec.yaml
js: ^0.6.3
<script>
functionjsBigIntModPow(bStr, eStr, mStr) {
let b = BigInt(bStr);
let e = BigInt(eStr);
let m = BigInt(mStr);
let bigIntOne = BigInt(1);
let bigIntZero = BigInt(0);
if (e < bigIntOne) {
return bigIntOne;
}
if (b < bigIntZero || b > m) {
b = b % m;
}
var r = bigIntOne;
while (e > bigIntZero) {
if ((e & bigIntOne) > bigIntZero) {
r = (r * b) % m;
}
e = e >> bigIntOne;
b = (b * b) % m;
}
return r;
}
</script>