I'm tring to get data of signed in user from microsoft azure using microsoft graph api,
i'm getting access token and also login successfully,
but i'm getting error as : "Insufficient privileges to complete the operation."
My Code
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:aad_oauth/aad_oauth.dart';
import 'package:aad_oauth/model/config.dart';
import 'package:exim_bank_leave_app/Utils/AppTheme.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Screens/Listing.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: MyTheme.darkTheme(context),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
static var user;
static final Config config = Config(
tenant: 'f6------------------38',
clientId: 'cba-----------------f5',
scope: 'openid profile offline_access',
redirectUri: 'https://login.microsoftonline.com/common/oauth2/nativeclient',
);
static final AadOAuth oauth = AadOAuth(config);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
SharedPreferences prefs;
static final String accessToken = accessToken;
var token;
#override
void initState() {
super.initState();
loadData();
}
#override
Widget build(BuildContext context) {
// adjust window size for browser login
var screenSize = MediaQuery.of(context).size;
var rectSize =
Rect.fromLTWH(0.0, 25.0, screenSize.width, screenSize.height - 25);
MyHomePage.oauth.setWebViewScreenSize(rectSize);
return Scaffold(
body: Container(),
);
}
loadData() async {
var auth = MyHomePage.oauth;
await auth.login();
var accessToken = await auth.getAccessToken();
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => Listing()));
prefs = await SharedPreferences.getInstance();
while (prefs == null || accessToken == null) continue;
final String idToken = await auth.getIdToken();
setState(() {
prefs.setString('token', idToken);
});
print('Token $accessToken');
final graphResponse = await http.get('https://graph.microsoft.com/v1.0/me',
headers: {HttpHeaders.authorizationHeader: "Bearer $accessToken"});
print(graphResponse.body.toString());
print(graphResponse.statusCode);
}
static void logout() async {
await MyHomePage.oauth.logout();
}
}
Error : I/flutter (29743): {"error":{"code":"Authorization_RequestDenied","message":"Insufficient privileges to complete the operation.","innerError":{"date":"2021-10-04T10:28:54","request-id":"3b12c615-47f1-4d07-ab4e-b6f4907a5b11","client-request-id":"3b12c615-47f1-4d07-ab4e-b6f4907a5b11"}}}
Based on your code 'https://graph.microsoft.com/v1.0/me' you are using the /me
When Calling the /me endpoint requires a signed-in user and therefore a delegated permission. Application permissions are not supported when using the /me endpoint .So Add the Delegated permission to call ApI
Delegated permissions are
User.Read,
User.ReadWrite,
User.ReadBasic.All,
User.Read.All,
User.ReadWrite.All,
Directory.Read.All,
Directory.ReadWrite.All,
Directory.AccessAsUser.All
To add the permission
1) Under an application's API permissions page, choose Add a permission.
2) select Microsoft Graph.
3) Choose the Delegated permission. And Search all the permission and Click on the Add Permission.
For more details refer this document
Related
Im experimenting and learning on a small project and im trying to implement an authentication workflow. Ive implemented everything and by printing my steps everything should just work fine. Im wondering why my BlocBuilder isn't going to update. The project is really small so I can provide you everything easy. Since im learning bloc, i appreciate every hint, approach and I want to thank you in advance.
terminal output when the app is starting:
flutter: building main.dart
flutter: AppLoaded()
flutter: user is NOT signed in
flutter: false
flutter: Transition { currentState: AuthInitial(), event: AppLoaded(), nextState: UnauthenticatedState() }
flutter: block says user is NOT authenticated
This is completely fine since im checking at the beginning if there is any user data valid. Now when I press on the Login Textbutton in my home.dart my Blocbuilder should show that im logged in, but it doesnt. This is the terminal output:
flutter: AppLoaded()
flutter: signed id with credentials: User{id: 1, socketId: 123, userName: Logged in User}
flutter: user is signed in
flutter: true
flutter: currentuser is not empty: User{id: 1, socketId: 123, userName: Logged in User}
flutter: Transition { currentState: AuthInitial(), event: AppLoaded(), nextState: AuthenticatedState() }
flutter: block says user is authenticated
main.dart
import 'package:fl_auth/bloc/auth/auth_bloc.dart';
import 'package:fl_auth/repositories/user_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'bloc/bloc_observer.dart';
import 'home.dart';
import 'models/auth.dart';
void main() {
BlocOverrides.runZoned(
() {
runApp(const MyApp());
},
blocObserver: SimpleBlocObserver(),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Auth _auth = Auth.instance;
UserRepository _userRepository = UserRepository(auth: _auth);
print('building main.dart');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider(
create: (context) =>
AuthBloc(userRepository: _userRepository)..add(AppLoaded()),
child: Home(),
),
);
}
}
home.dart
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'bloc/auth/auth_bloc.dart';
import 'models/auth.dart';
import 'repositories/user_repository.dart';
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Auth _auth = Auth.instance;
UserRepository _userRepository = UserRepository(auth: _auth);
AuthBloc authBloc = AuthBloc(userRepository: _userRepository);
return Scaffold(
body: SizedBox(
height: 500,
child: Column(
children: [
Container(
height: 200,
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is UnauthenticatedState) {
return Center(child: Text('User is unauthenticated'));
} else if (state is AuthenticatedState) {
return Center(child: Text('YEAH logged in!'));
} else {
return Center(child: Text('something went wrong'));
}
}),
),
TextButton(
onPressed: () => {
authBloc.userRepository.signIn(),
authBloc.add(AppLoaded())
},
child: Text('Login')),
],
)));
}
}
auth_event.dart
part of 'auth_bloc.dart';
abstract class AuthEvent extends Equatable {
const AuthEvent();
#override
List<Object> get props => [];
}
class AppLoaded extends AuthEvent {}
auth_state.dart
// ignore_for_file: public_member_api_docs, sort_constructors_first
part of 'auth_bloc.dart';
abstract class AuthState extends Equatable {
const AuthState();
#override
List<Object> get props => [];
}
class AuthInitial extends AuthState {}
class AuthenticatedState extends AuthState {
User user;
AuthenticatedState({
required this.user,
});
}
class UnauthenticatedState extends AuthState {}
auth.bloc
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:fl_auth/repositories/user_repository.dart';
import '../../models/user.dart';
part 'auth_event.dart';
part 'auth_state.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
UserRepository userRepository;
AuthBloc({required this.userRepository}) : super(AuthInitial()) {
on<AppLoaded>((event, emit) async {
try {
var isSignedIn = await userRepository.isSignedIn();
print(isSignedIn);
if (isSignedIn) {
var user = await userRepository.getCurrentUser();
emit(AuthenticatedState(user: user));
print('block says user is authenticated');
} else {
emit(UnauthenticatedState());
print('block says user is NOT authenticated');
}
} catch (e) {
emit(UnauthenticatedState());
}
});
}
}
user_repository.dart
import 'package:fl_auth/models/user.dart';
import '../models/auth.dart';
class UserRepository {
Auth auth = Auth.instance;
UserRepository({required this.auth});
// sign in with username
//TODO: change hardcoded username to email and passwort later on
Future<User> signIn() async {
try{
await Future.delayed(Duration(seconds: 1));
var credentials = User(id: 1, socketId: '123', userName: 'Logged in User');
print('signed id with credentials: ${auth.currentUser}');
auth.currentUser = credentials;
return auth.currentUser;
}catch(e){
print(e.toString());
throw e;
}
}
// check signed in status
Future<bool> isSignedIn() async {
try{
await Future.delayed(const Duration(seconds: 1));
var currentUser = auth.currentUser;
if(currentUser.isNotEmpty){
print('user is signed in');
return true;
} else {
print('user is NOT signed in');
return false;
}
}catch(e){
print(e.toString());
throw e;
}
}
// get user
Future<User> getCurrentUser() async {
try{
await Future.delayed(const Duration(seconds: 1));
var currentUser = auth.currentUser;
if(currentUser.isNotEmpty){
print('currentuser is not empty: $currentUser');
return currentUser;
} else {
var message = 'User is empty';
print('currentuser IS empty: $currentUser');
throw message;
}
}catch(e){
print(e.toString());
throw e;
}
}
}
auth.dart
import 'user.dart';
class Auth {
/// private constructor
Auth._();
/// the one and only instance of this singleton
static final instance = Auth._();
//ChatBloc chatBloc = ChatBloc(DatabaseApi.db);
// Create a User instance. Actually it would be better if this is empty so I can notice if a user is valid or not and can react by checking if the user has values and
// if not log the user out later on
User currentUser = User.empty;
}
user.dart
import 'package:equatable/equatable.dart';
/// {#template user}
/// User model
///
/// [User.empty] represents an unauthenticated user.
/// {#endtemplate}
class User extends Equatable {
/// {#macro user}
const User({
required this.id,
this.socketId,
this.userName,
});
/// The current user's scoket id.
final String? socketId;
/// The current user's id.
final int id;
/// The current user's name (display name).
final String? userName;
/// Empty user which represents an unauthenticated user.
static const empty = User(id: 0);
/// Convenience getter to determine whether the current user is empty.
bool get isEmpty => this == User.empty;
/// Convenience getter to determine whether the current user is not empty.
bool get isNotEmpty => this != User.empty;
#override
List<Object?> get props => [id, socketId, userName];
// Convert a user into a Map. The keys must correspond to the names of the
// columns in the database.
Map<String, dynamic> toMap() {
return {
'id': id,
'socketId': socketId,
'userName': userName,
};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'] as int,
socketId: map['socketId'] as String,
userName: map['userName'] as String,
);
}
// Implement toString to make it easier to see information about
// each user when using the print statement.
#override
String toString() {
return 'User{id: $id, socketId: $socketId, userName: $userName}';
}
}
The issue is In your OnTap Function you can call Event like this. I have checked and It's working as expected.
TextButton(
onPressed: () => {
authBloc.userRepository.signIn(),
context.read<AuthBloc>().add(AppLoaded())
},
child: const Text('Login')),
I am needing to encrypt a hive box, in which the box 'user_api' is to be called in Api_Page_() to receive user input to store inside said box. However, the encryptedBox is not defined within the class. The Hive Docs display the encryption code is to be done inside of the main() function, which I have done, but I am unsure of how to take the box outside of main().
Any help or advice is greatly appreciated!
My Code:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// HIVE ENCRYPTION----------------------------------------
const secureStorage = FlutterSecureStorage();
final encryptionKey = await secureStorage.read(key: 'key');
if (encryptionKey == null) {
final key = Hive.generateSecureKey();
await secureStorage.write(
key: 'key',
value: base64Encode(key),
);
}
final key = await secureStorage.read(key: 'key');
final encryptKey = base64Url.decode(key);
print('Encryption key: $encryptKey');
// HIVE ENCRYPTION----------------------------------------
// HIVE INIT---------------------------------------------
Directory directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
await Hive.initFlutter();
final encryptedBox = Hive.openBox<String>('user_api', encryptionCipher: HiveAesCipher(encryptKey)); // Initially Opens Box on App Start
// HIVE INIT---------------------------------------------
runApp(myApp());
}
class myApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false, // Removes Debug Banner. [Delete before app release]
title: 'App Title Placeholder',
home: API_Page_() // Calls API_Page_ class from api_page.dart
);
}
}
class API_Page_ extends StatelessWidget {
const API_Page_({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(onPressed: () { var eBox = encryptedBox<String>('user_api');
},
)
);
}
}
I want to create http client and I want to use that http client in entire app. Creating http client is not a big deal but I want to add token in header which I get after login.
Right now I'm doing like this:
web_api_service.dart
Here I'm creating http client with dio package with the token after login
class WebApiService{
final String? tokenKey;
WebApiService(this.tokenKey);
Dio _dio = Dio();
Dio get dio {
_dio.options.baseUrl = BASE_URL;
_dio.options.headers = {'token': '$tokenKey'};
return _dio;
}
Future<List<SessionData>?> upcomingSessionData(SessionRequest request) async{
List<SessionData>? sessions;
try{
var response = await dio.post('/session/upcommingSession', data: sessionRequestToJson(request));
final responseMap = response.data;
// print(responseMap);
if(response.statusCode == 200){
if(responseMap['status'] == "Success"){
final data = upcomingSessionFromJson(jsonEncode(responseMap));
sessions = data.data;
print(responseMap);
return sessions;
}
}
} catch (e){
print(e);
rethrow;
}
return sessions;
}
}
main.dart
To get token from Auth I have created a ProxyProvider
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Auth()),
ProxyProvider<Auth, WebApiService>(update: (_, auth, __) => WebApiService(auth.tokenKey)),
],
child: Home(),
);
}
}
home.dart
Here I'm using FutureBuilder to get the data from api
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final _api = Provider.of<WebApiService>(context, listen: false);
return FutureBuilder<List<SessionData>?>(
future: _api.upcomingSessionData(SessionRequest(
trainerId: "110006",
lat: "17.387140",
lng: "78.491684",
role: "Admin"
)),
builder: (BuildContext context, AsyncSnapshot<List<SessionData>?> snapshot){
return SomeWidget();
}
}
}
}
What I want?
I don't want to use FutureBuilder instead I want to call the api from a controller to separate the UI from business logic.
I want to create a http client with token key in header (I get token after login) which I can use in entire app.
Any positive feedback is also appreciated
In a case like this, I often use injector for it. for example using get_it
You can register a singleton to save the token values that you get from authentication logic. let say that we save the token on AuthModel object.
for example:
final getIt = GetIt.instance;
class AuthModel {
String? token;
AuthModel({this.token});
}
void setup() {
getIt.registerSingleton<AuthModel>(AuthModel());
}
call these setup at main, before everything else is called.
then when we need to update the token, or get the value of these token, just simply call the getIt anywhere in the project.
getIt<AuthModel>().token = NEW_TOKEN;
var savedToken = getIt<AuthModel>().token;
I am creating a Login , Logout Page in flutter when i use Stream and Provider . I get Some Errors.
Help me out of this
in the main.dart when i use the StreamProvider it says the intial data cannot be null, according to my Tutorial there is no intialdata and in auth.dart when i use the authStatchanges().map it gives me 'The argument type 'Userid Function(User)' can't be assigned to the parameter type 'Userid Function(User?)'
Error Places - auth change user stream & and StreamProvider in main.dart
Thanks
Auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:wasthu/Services/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
//create userobject based on firebase user
Userid? _userFromFirebaseUser(User user) {
return user != null ? Userid(uid: user.uid) : null;
}
// auth change user stream
Stream<Userid> get user {
return _auth
.authStateChanges()
.map((User user) => _userFromFirebaseUser(user));
}
//sign in anon
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User? user = result.user;
return _userFromFirebaseUser(user!);
} catch (e) {
print(e.toString());
return null;
}
}
//signout
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:wasthu/Screens/Home/wrapper.dart';
import 'package:wasthu/Services/auth.dart';
import 'package:wasthu/Services/user.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
home: MyApp(),
debugShowCheckedModeBanner: false,
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamProvider<Userid>.value(
value: AuthService().user,
initialData: null,
child: MaterialApp(
home: Wrapper(),
),
);
}
}
user.dart
class Userid {
final String uid;
Userid({required this.uid});
}
I'm create a project on Flutter. And I'm using a provider to change screens in my app.
Here is my main.dart file:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/services/auth_service.dart';
import 'package:school_app/wrapper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthService().auth,
child: MaterialApp(
home: Wrapper(),
),
);
}
}
Also this is my wrapper.dart file where the screens choose:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/screens/authenticate/auth.dart';
import 'package:school_app/models/user.dart';
import 'package:school_app/screens/school/home.dart';
import 'package:school_app/services/auth_service.dart';
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<AuthProvider>(context);
print(user.auth);
if(!user.auth) return Auth();
return Home();
}
}
And it is my AuthProvider class:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
/* AuthUser _user(User user) {
return user != null ? AuthUser(uid: user.uid) : null;
}*/
AuthProvider auth = new AuthProvider();
//sign in
Future signIn(String username, String password) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
var dio = Dio();
Response user = await dio.post('url', data: {
'username': username,
'password': password
});
if(user.data['success'] == false) return user.data['msg'];
await prefs.setString('token', user.data['token']);
auth.setAuth(true);
print("SUCCESS");
} catch(e) {
print('Error ' + e.toString());
}
}
}
class AuthProvider with ChangeNotifier {
bool _auth;
AuthProvider() {
_auth = false;
}
bool get auth => _auth;
void setAuth(bool auth) {
_auth = auth;
notifyListeners();
}
}
And when I call a function in AuthProvider class setAuth, nothing changed. Can you help me and find my mistake?
EDIT
I'm making all changes that you writes but it is not working. Here is my main.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/services/auth_service.dart';
import 'package:school_app/wrapper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthProvider(),
child: MaterialApp(
home: Wrapper(),
),
);
}
}
Also wrapper.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/screens/authenticate/auth.dart';
import 'package:school_app/screens/school/home.dart';
import 'package:school_app/services/auth_service.dart';
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
#override
void initState() {
// TODO: implement initState
super.initState();
AuthService().auth;
}
#override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (context, authProvider, child) {
print(authProvider.auth);
if (!authProvider.auth) {
return Auth();
} else {
return Home();
}
});
}
}
And AuthService and AuthProvider classes:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
/* AuthUser _user(User user) {
return user != null ? AuthUser(uid: user.uid) : null;
}*/
AuthProvider auth = new AuthProvider();
//sign in
Future signIn(String username, String password) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
var dio = Dio();
Response user = await dio.post('url', data: {
'username': username,
'password': password
});
if(user.data['success'] == false) return user.data['msg'];
await prefs.setString('token', user.data['token']);
auth.setAuth(true);
print("SUCCESS");
} catch(e) {
print('Error ' + e.toString());
}
}
}
class AuthProvider with ChangeNotifier {
bool _auth;
AuthProvider() {
_auth = false;
}
bool get auth => _auth;
void setAuth(bool auth) {
_auth = auth;
notifyListeners();
}
}
Notice, that here two classes and in AuthService I'm calling function .setAuth(true).
In your current implementation of Wrapper, you are rendering the widget once and not listening to whether the values changed. You could use Consumer as suggested above. You could also choose to watch the value for changes - like this:
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = context.watch<AuthProvider>();
print(user.auth);
if(!user.auth) return Auth();
return Home();
}
}
When you use a watch or Consumer pattern, the widget will be rendered when the values of the underlying store (which is AuthProvider here) gets changed.
The only missing part here is that you never Consume the AuthProvider to listen to the notifyListeners() trigger.
The correct implementation looks like the following (I didn't try it, you may have to correct some typo errors, but you'll get the idea !)
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(
builder: (context, authProvider, child) {
if (!authProvider.auth) {
return Auth();
} else {
return Home();
}
}
);
}
}
EDIT
I didn't notice you weren't injecting the right Class in your ChangeNotifierProvider. You'll also have to update your widget MyApp
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthProvider(),
child: MaterialApp(
home: Wrapper(),
),
);
}
And in this case you probably should transform your Wrapper widget to a Stateful widget, and in the initState method you should call AuthService().auth.
I strongly recommend you to read the official documentation of Provider, looks like things aren't crystal clear yet in your mind
EDIT 2
You're still missing the point of the Provider library.
The goal of this lib is to provide an instance of a class to your widget tree so you don't have to re-create an instance in each widget.
Here, in AuthService class you're re-creating a AuthProvider with AuthProvider auth = new AuthProvider(); instead of referring to the existing instance created in the parent Widget.
To refer to a previously created instance, you should use Provider.of<AuthProvider>(context); in the AuthService class, or, even better, pass the instance of AuthProvider as a parameter in the signIn method.