Closed oysterpack closed 4 years ago
Correct, CognitoUserPool doesn't contain session while CognitoUser does.
I solved the problem ... in order to restore the session, tokens need to be cached, e.g.,
final cognitoUser = CognitoUser(
userEmail,
userPool,
storage: userPool.storage,
);
final authDetails = AuthenticationDetails(
username: userEmail,
password: password,
);
await cognitoUser.authenticateUser(authDetails);
// in order to restore the session later on, the session tokens need to be cached into CognitoStorage
await cognitoUser.cacheTokens();
final currentUser = await userPool.getCurrentUser();
final currentSession = await currentUser.getSession();
expect(currentSession.isValid(), isTrue);
This should be documented or at least included in the example, I just lost hours debugging while the answer was just a single line of code.
How come this is not default behaviour @furaiev? Do you know?
Seems like it would make a lot of sense to always persist/cache all persistable data if a Storage mechanism is in place?
Update from my experience from the latest non null safety version: this is only needed for non-web platforms, on web it precaches the tokens automatically (tested on web, macOS, and iOS).
@pal this package is based on https://github.com/aws-amplify/amplify-js I'm not sure why this is not the default behavior in the official package.
I solved the problem ... in order to restore the session, tokens need to be cached, e.g.,
final cognitoUser = CognitoUser( userEmail, userPool, storage: userPool.storage, ); final authDetails = AuthenticationDetails( username: userEmail, password: password, ); await cognitoUser.authenticateUser(authDetails); // in order to restore the session later on, the session tokens need to be cached into CognitoStorage await cognitoUser.cacheTokens(); final currentUser = await userPool.getCurrentUser(); final currentSession = await currentUser.getSession(); expect(currentSession.isValid(), isTrue);
I tried caching on login in user_service then printing in user_service init like this:
/// Login user
Future<User?> login(String email, String password) async {
_cognitoUser = CognitoUser(email, _userPool, storage: _userPool.storage);
final authDetails = AuthenticationDetails(
username: email,
password: password,
);
bool isConfirmed;
try {
_session = await _cognitoUser?.authenticateUser(authDetails);
//cache session tokens to persist
//https://github.com/furaiev/amazon-cognito-identity-dart-2/issues/82#issuecomment-669139576
await _cognitoUser?.cacheTokens();
//rest of code is unchanged
/// Initiate user session from local storage if present
Future<bool> init() async {
String keyPrefix =
'CognitoIdentityServiceProvider.${_cognitoUser?.pool.getClientId()}?.${_cognitoUser?.username}';
late final idTokenKey;
late final accessTokenKey;
late final refreshTokenKey;
late final clockDriftKey;
//call getKeys() new method for debug
List<dynamic> allKeys = await _cognitoUser?.storage.getKeys();
print('\n\nall keys: $allKeys\n\n');
idTokenKey = await _cognitoUser?.storage.getItem('$keyPrefix.idToken');
accessTokenKey =
await _cognitoUser?.storage.getItem('$keyPrefix.accessToken');
refreshTokenKey =
await _cognitoUser?.storage.getItem('$keyPrefix.refreshToken');
clockDriftKey =
await _cognitoUser?.storage.getItem('$keyPrefix.clockDrift');
print(
'idTokenKey: $idTokenKey.toString\n\n accessTokenKey: $accessTokenKey\n\n refreshTokenKey: $refreshTokenKey\n\n, clockDriftKey: $clockDriftKey');
But it's printing null
I/flutter (11124): , clockDriftKey: null
I/flutter (11124): idTokenKey: null
I/flutter (11124):
I/flutter (11124): accessTokenKey: null
I/flutter (11124):
I/flutter (11124): refreshTokenKey: null
I/flutter (11124):
I/flutter (11124): , clockDriftKey: null
I/flutter (11124):
And you can see above I added an addKeys()
method for cognito_storage.dart and all the child classes which leads to a hang on the Login... in the appbar.
abstract class CognitoStorage {
Future<dynamic> setItem(String key, value);
Future<dynamic> getItem(String key);
Future<dynamic> removeItem(String key);
Future<void> clear();
Future<dynamic> getKeys();
}
class CognitoMemoryStorage extends CognitoStorage {
@override
Future<dynamic> setItem(String key, value) async {
_dataMemory[key] = value;
return _dataMemory[key];
}
@override
Future<dynamic> getItem(String key) async {
return _dataMemory[key];
}
@override
Future<dynamic> removeItem(String key) async {
return _dataMemory.remove(key);
}
@override
Future<void> clear() async {
_dataMemory = {};
}
//return keys
@override
Future<dynamic> getKeys() async {
return _dataMemory.keys;
}
}
I solved the problem ... in order to restore the session, tokens need to be cached, e.g.,
final cognitoUser = CognitoUser( userEmail, userPool, storage: userPool.storage, ); final authDetails = AuthenticationDetails( username: userEmail, password: password, ); await cognitoUser.authenticateUser(authDetails); // in order to restore the session later on, the session tokens need to be cached into CognitoStorage await cognitoUser.cacheTokens(); final currentUser = await userPool.getCurrentUser(); final currentSession = await currentUser.getSession(); expect(currentSession.isValid(), isTrue);
How do you retrieve the tokens?
I would expect that if the user is authenticated, then the current user should be associated with a session. The current implementation never associates a session: