Skip to content

Commit 5304525

Browse files
committed
feat: add cognito credentials storing
1 parent ac216e5 commit 5304525

File tree

5 files changed

+80
-3
lines changed

5 files changed

+80
-3
lines changed

lib/cognito/auth_api_http_client.dart

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ enum kAuthErrorResolving
1717
retry,
1818
}
1919

20+
// ignore: camel_case_types
21+
enum kAuthError
22+
{
23+
invalid,
24+
expired,
25+
signedOut,
26+
}
27+
2028
// ignore: camel_case_types
2129
enum kHttpMethod
2230
{
@@ -58,7 +66,7 @@ typedef GetAuthToken = Future<String?> Function();
5866
typedef GetBaseUrl = Future<String> Function();
5967
typedef GetDefaultHeaders = Future<Map<String, String>> Function();
6068
typedef CreateResponseObject<T> = T Function(int statusCode, Map<String, dynamic>? jsonPayload);
61-
typedef AuthError = Future<kAuthErrorResolving> Function(ApiAuthException exception, kAuthRequirement authRequirement);
69+
typedef AuthError = Future<kAuthErrorResolving> Function(kAuthError error, kAuthRequirement authRequirement);
6270

6371
class AuthApiHttpClient<TResponse> {
6472

@@ -248,16 +256,20 @@ class AuthApiHttpClient<TResponse> {
248256
{
249257
Dev.logException(this, e, 'Failed $method to $apiPath');
250258

251-
if (e is ApiAuthException)
259+
if (e is ApiAuthException || e is SignedOutException)
252260
{
253-
final authErrorResolving = await onAuthError(e, authRequirement);
261+
kAuthError authError = e is SignedOutException ? kAuthError.signedOut : (e as ApiAuthException).code == kApiAuthExceptionCode.tokenExpired ? kAuthError.expired : kAuthError.invalid;
262+
263+
final authErrorResolving = await onAuthError(authError, authRequirement);
254264

255265
if (authErrorResolving == kAuthErrorResolving.cancelWithRethrow)
256266
{
257267
rethrow;
258268
}
259269
else if (authErrorResolving == kAuthErrorResolving.retry)
260270
{
271+
await 1000.delay();
272+
261273
return makeRequest(
262274
apiPath: apiPath,
263275
body: body,
@@ -270,6 +282,16 @@ class AuthApiHttpClient<TResponse> {
270282
}
271283
}
272284

285+
if (e is NetworkException)
286+
{
287+
throw ApiResponseNoNetwork();
288+
}
289+
290+
if (e is ClientException && e.message.startsWith('Failed host lookup'))
291+
{
292+
throw ApiResponseNoNetwork();
293+
}
294+
273295
rethrow;
274296
}
275297

lib/cognito/cognito_service.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ enum kSignInResult
1212

1313
abstract class AuthService extends CustomService {
1414

15+
Future<void> updateStoredPassword(String password);
16+
Future<void> updateStoredEmail(String email);
17+
18+
Future<CognitoSignInResult> signInUsingStoreCredentials();
1519
Future<CognitoSignInResult> signIn(String email, String password);
1620
Future<CognitoForgotPasswordRequestResult> forgotPasswordRequest(String email);
1721
Future<CognitoResetPasswordResult> resetPasswordRequest(String email, String newPassword, String confirmationCode);
@@ -26,6 +30,7 @@ abstract class AuthService extends CustomService {
2630
class CognitoAuthenticationService extends AuthService {
2731

2832
final String config;
33+
late final FlutterSecureStorage _secureStorage;
2934

3035
CognitoAuthenticationService(this.config);
3136

@@ -35,6 +40,36 @@ class CognitoAuthenticationService extends AuthService {
3540
{
3641
await Amplify.addPlugin(AmplifyAuthCognito());
3742
await Amplify.configure(config);
43+
44+
_secureStorage = const FlutterSecureStorage();
45+
46+
}
47+
48+
@override
49+
Future<void> updateStoredPassword(String password) async
50+
{
51+
await _secureStorage.write(key: 'COGNITO_PASSWORD', value: password);
52+
}
53+
54+
@override
55+
Future<void> updateStoredEmail(String email) async
56+
{
57+
await _secureStorage.write(key: 'COGNITO_EMAIL', value: email);
58+
}
59+
60+
61+
@override
62+
Future<CognitoSignInResult> signInUsingStoreCredentials() async
63+
{
64+
String? email = await _secureStorage.read(key: 'COGNITO_EMAIL');
65+
String? password = await _secureStorage.read(key: 'COGNITO_PASSWORD');
66+
67+
if (email == null || password == null)
68+
{
69+
return CognitoSignInResult(exception: Exception('No stored credentials'));
70+
}
71+
72+
return signIn(email, password);
3873
}
3974

4075
@override
@@ -56,6 +91,8 @@ class CognitoAuthenticationService extends AuthService {
5691
attributes = await Amplify.Auth.fetchUserAttributes();
5792
}
5893

94+
await _secureStorage.write(key: 'COGNITO_EMAIL', value: email);
95+
await _secureStorage.write(key: 'COGNITO_PASSWORD', value: password);
5996

6097
return CognitoSignInResult(data: SignInResultExtended(
6198
signInResult: result,
@@ -121,6 +158,9 @@ class CognitoAuthenticationService extends AuthService {
121158
Future<void> signOut() async
122159
{
123160
await Amplify.Auth.signOut();
161+
162+
await _secureStorage.delete(key: 'COGNITO_EMAIL');
163+
await _secureStorage.delete(key: 'COGNITO_PASSWORD');
124164
}
125165

126166
@override

lib/devspace.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ import 'package:flutter/services.dart';
2020
import 'package:flutter/widgets.dart';
2121
import 'package:flutter_animate/flutter_animate.dart';
2222
import 'package:flutter_image_compress/flutter_image_compress.dart';
23+
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2324
import 'package:get_it/get_it.dart';
2425
import 'package:go_router/go_router.dart';
2526
import 'package:http/http.dart' as http;
27+
import 'package:http/http.dart';
2628
import 'package:image_picker/image_picker.dart';
2729
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
2830
import 'package:loading_indicator/loading_indicator.dart';

lib/models/api/api_responses.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ class ApiResponse {
7373
}
7474
}
7575

76+
class ApiResponseNoNetwork implements Exception, UserFriendlyException {
77+
78+
final String message;
79+
ApiResponseNoNetwork([this.message = 'No network available. Please check your internet connection.']);
80+
81+
@override
82+
String toString() => 'ApiResponseNoNetwork: $message';
83+
// TODO: use localized strings
84+
@override
85+
String toUserFriendlyMessage(bool forEmployee) => forEmployee ? toString() : 'No network available. Please check your internet connection.';
86+
}
87+
7688
class ApiResponseInvalidException implements Exception, UserFriendlyException {
7789

7890
final String message;

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ dependencies:
3535
flutter_image_compress: ^2.3.0
3636
app_settings: ^5.1.1
3737
package_info_plus: ^6.0.0
38+
flutter_secure_storage: ^4.2.1
3839

3940
dev_dependencies:
4041
flutter_test:

0 commit comments

Comments
 (0)