I am using Amplify with Flutter to do the user authentication but I can't retrieve the user's session. The error I get:
> Launching lib/main.dart on 2109119DG in debug mode...
Running Gradle task 'assembleDebug'...
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Debug service listening on ws://xxxx
Syncing files to device 2109119DG...
I/amplify:flutter:auth_cognito(27806): Added Auth plugin
E/flutter (27806): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: AmplifyException(message: Auth plugin has not been added to Amplify, recoverySuggestion: Add Auth plugin to Amplify and call configure before calling Auth related APIs, underlyingException: null)
E/flutter (27806): #0 AuthCategory.fetchAuthSession (package:amplify_core/src/category/amplify_auth_category.dart:189:11)
E/flutter (27806): #1 _MyAppState.isUserSignedIn (package:base_app/main.dart:37:39)
E/flutter (27806): #2 _MyAppState.build (package:base_app/main.dart:47:21)
E/flutter (27806): #3 StatefulElement.build (package:flutter/src/widgets/framework.dart:4992:27)
E/flutter (27806): #4 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4878:15)
E/flutter (27806): #5 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
E/flutter (27806): #6 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
E/flutter (27806): #7 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4859:5)
E/flutter (27806): #8 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5041:11)
E/flutter (27806): #9 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4853:5)
E/flutter (27806): #10 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
E/flutter (27806): #11 Element.updateChild (package:flutter/src/widgets/framework.dart:3592:18)
E/flutter (27806): #12 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1195:16)
E/flutter (27806): #13 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1164:5)
E/flutter (27806): #14 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1111:18)
E/flutter (27806): #15 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2605:19)
E/flutter (27806): #16 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1110:13)
E/flutter (27806): #17 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:945:7)
E/flutter (27806): #18 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:925:7)
E/flutter (27806): #19 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
E/flutter (27806): #20 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
E/flutter (27806): #21 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
E/flutter (27806): #22 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
E/flutter (27806):
D/AWSMobileClient(27806): Using the SignInProviderConfig from `awsconfiguration.json`.
D/AWSMobileClient(27806): Inspecting user state details
I/flutter (27806): Successfully configured
D/AWSMobileClient(27806): Inspecting user state details
I/TetheringManager(27806): registerTetheringEventCallback:com.dontknow.base_app
D/AWSMobileClient(27806): hasFederatedToken: false provider: cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxx
D/AWSMobileClient(27806): hasFederatedToken: false provider: cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxx
D/AWSMobileClient(27806): Inspecting user state details
D/AWSMobileClient(27806): hasFederatedToken: true provider: cognito-idp.eu-central-1.amazonaws.com/eu-central-1_xxxx
D/AWSMobileClient(27806): waitForSignIn: userState:SIGNED_IN
D/AWSMobileClient(27806): getCredentials: Validated user is signed-in
I strictly folloed the AWS tutorials and added the plugin before calling "configure" in the code. What is also odd, is that in the line before the error occurs the plugin is actually loaded.
Here is my main.dart:
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_configureAmplify();
}
void _configureAmplify() async {
try {
await Amplify.addPlugin(AmplifyAuthCognito());
await Amplify.configure(amplifyconfig);
print('Successfully configured');
} on Exception catch (e) {
print('Error configuring Amplify: $e');
}
}
Future<bool> isUserSignedIn() async {
final result = await Amplify.Auth.fetchAuthSession();
return result.isSignedIn;
}
@override
Widget build(BuildContext context) {
return Authenticator(
child: MaterialApp(
builder: Authenticator.builder(),
home: FutureBuilder(
future: isUserSignedIn(),
builder: (BuildContext ctx, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return Text("logged in");
}
}),
),
);
}
}
CodePudding user response:
You are trying to do asynchronous work in initState()
, but this is not guaranteed to complete before build()
is called. Therefore, when you call Amplify.Auth.fetchAuthSession()
in your build()
function, the initialisation and configuration is not complete.
You should try calling _configureAmplify()
before runApp()
.
To make this work, you also need to call WidgetsBinding ensureInitialized()
before _configureAmplify()
.
As a general advise, this kind of work does not belong into UI code (pages or widgets). Rather is should be done in the app's state management.
CodePudding user response:
Finally I found a suitable fix fitting my skilllevel here github-repo
I added a state variable _isAmplifyConfigured
which is set true when _configureAmplify()
finishes. In the builder I then check wheter amplify is configured or not with a simple if-else. Here the full code:
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'amplifyconfiguration.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isAmplifyConfigured = false;
@override
void initState() {
super.initState();
_configureAmplify();
}
void _configureAmplify() async {
try {
await Amplify.addPlugin(AmplifyAuthCognito());
await Amplify.configure(amplifyconfig);
setState(() => _isAmplifyConfigured = true);
print('Successfully configured');
} on Exception catch (e) {
print('Error configuring Amplify: $e');
}
}
Future<bool> isUserSignedIn() async {
final result = await Amplify.Auth.fetchAuthSession();
return result.isSignedIn;
}
@override
Widget build(BuildContext context) {
return Authenticator(
child: MaterialApp(
builder: Authenticator.builder(),
home: _isAmplifyConfigured? FutureBuilder(
future: isUserSignedIn(),
builder: (BuildContext ctx, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
return Text("logged in");
}
}): Text("not logged in")
),
);
}
}