How to implement Authentication using Riverpod in Flutter? - flutter

I have three providers for login => email, password, login.
then I am refreshing login provider which is a future provider and will call the login API.
now I need to see if the provider returns success then I will need to navigate to next page.
But .when() is not waiting for the refreshing to finish. Its logging "loading..." in the console.
`
ref.watch(email.notifier).state =
emails.trim().toLowerCase();
ref.watch(password.notifier).state = passwords;
final loginstate = ref.refresh(login);
loginstate.when(data: ((data) {
// log(data + "here");
if (data == "Success") {
context.go('/home');
}
}), error: (error, stackTrace) {
// log(error.toString() + "here");
}, loading: () {
log("loading....");
});
`
I need to Navigate to the Home page upon successful API call.

Related

is there a way to get response from a request sent from browser in flutter app

I have a flutter app where users are required to pay to see some content the payment is done with pay pal and after the payment is done from the browser/web view then a request is sent to the backend and the backend will send the token to the webpage so I want to access that token in the app to check if the payment was successful to open the payment page I use
_launchURLApp() async {
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
} else {
throw 'Could not launch $url';
}
}
onTap: () {
ApiClient.payWithPayPal().then((response) => {
setState(() {
url = response;
}),
_launchURLApp()
});
}

next-auth pass the data in signin callback

I am making login process with next-auth.
I am using Google as OAuth Provider.
// pages/api/auth/[...nextauth].ts
export default async function auth(req: any, res: any) {
return await NextAuth(req, res, {
//...
callbacks: {
async signIn({ user, account }) {
// console.log(user); // data exists.
const isUser = await apiForIsUser();
if(isUser) return true; // redirect to root page.
return '/sign-up'; // redriect to sign-up page.
}
}
});
}
above code works, but I can not touch data from OAuthProvider in sign-up page.
How can I pass the data from 'OAuthProvidertosign-up` page?

how to redirect user to logout page when token or refresh token expired using bloc in flutter

This is my base repository where it gets the data from the bloc I want to redirect the user to a custom page like logout when the token expires or refresh token expire. I change pages, in bloc consumer or bloc listener but in this case, this is stupid work because I should replace bloc consumer with another bloc method everywhere I request to the server
#override
Future<Map<String, dynamic>> get(String url) async {
// Uri newUrl = Uri.parse(baseUrl + url);
var newUrl = baseUrl + url;
dio.Response response;
try {
// x.interceptors.add(dio.InterceptorsWrapper(
// onError: (e, handler) {
// if(e.response!.statusCode == 401)
// redirect user to custom page
// },
// ));
response = await dio.Dio()
.get(newUrl, options: dio.Options(headers: headersList))
.timeout(duration);
var result = _processResponse(response);
if (result.runtimeType.toString().toLowerCase() == 'string') {
return <String, String>{'key': result};
}
return result;
} on SocketException {
throw FetchDataException('internetConnection');
} on TimeoutException {
throw ApiNotRespondingException('api not found ');
} on Exception catch (e) {
var response = e as dio.DioError;
print(e.toString());
throw _handleError(response);
}
}
I recently asked myself the same question and come up with this solution (maybe not the best one).
You need a separated bloc for containing jwt tokens;
Init this bloc as a singleton. I use injectable that uses get_it as a DI
#singleton
class TokenBloc extends Bloc<TokenEvent, TokenState> {
final ISecureStorage secureStorage;
TokenBloc(this.secureStorage) : super(TokenInitial()) {
on<TokenReseted>(delete);
on<TokenUpdated>(put);
}
put(event, emit) {
emit(TokenAuthentificated(event.accessToken, event.refreshToken));
secureStorage.write('accessToken', event.accessToken);
secureStorage.write('refreshToken', event.refreshToken);
}
delete(event, emit) {
emit(TokenDeleted());
emit(TokenInitial());
secureStorage.write('accessToken', null);
secureStorage.write('refreshToken', null);
}
}
Wrap your Home widget with BlocProvider like that
return BlocProvider.value(
value: getIt.get<TokenBloc>(),
child: const CupertinoApp(
home: Home(),
),
);
Create a single module for requesting a new refresh token from API, which will use this TokenBloc for updating/deleting tokens. You can access to TokenBloc from RefreshTokenAPI using getIt.
getIt.get<TokenBloc>().add(TokenReseted());
All you have to do is to listen to the TokenBloc changes in your UI and make a redirect.
That’s it. Hope it will help :)

linkWithCredential and Flutter Web with Apple

I have a use case where a user, on Flutter Web, needs to link an Apple auth with their existing account, and the email may not match.
However, the only available method for Flutter Web Apple Authentication is signInWithPopUp. If the user's apple email is different from the User firebase account email, a new firebase account is created, and a user is returned, short circuiting the process of linking, this creates a new account in firebase, and I'm unable to linkWithCredential.
My method to try to link accounts is as follows:
Future<String> linkWithAppleWeb() async {
try {
final User user = _auth.currentUser!;
final provider = OAuthProvider("apple.com")
..addScope('email')
..addScope('name');
await _auth.signInWithPopup(provider).then((appleCredential) async {
final authCredential = appleCredential.credential;
await user.linkWithCredential(authCredential!).then((result) {
DatabaseService().updateUserSocialAuth(user.uid, 'apple');
return 'Success';
}).catchError((e) {
return 'Error: $e';
});
});
} catch (e) {
return 'Error: $e';
}
return 'Success';
}
As you would expect, my project starts with Streaming a User Object, and when the pop up signs in, it returns the new user, which rebuilds the entire project. Is there a way to authenticate an apple user without returning a new user? I can link a google or phone authorization method fine. It's apple that is problematic. I don't fully understand why Google doesn't break in the same way, other than Firebase put in the work to ensure the functionality of linking for GoogleSignIn().signIn() I'm not using other social auth methods, and I don't use password/email.
This method is not documented in the Flutter Fire Docs, but works perfectly:
Future<String> linkWithAppleWeb() async {
try {
final User user = _auth.currentUser!;
final provider = OAuthProvider("apple.com")
..addScope('email')
..addScope('name');
await user.linkWithPopup(provider).then((result) {
DatabaseService().updateUserSocialAuth(user.uid, 'apple');
return 'Success';
}).catchError((e) {
return 'Error: $e';
});
} catch (e) {
debugPrint('auth linkWithGoogle error: ${e.toString()}');
return 'Error: $e';
}
return 'Success';
}

Google Auth Page always shown, how to Auth only first time

I am making a calendar app with flutter using googleApi library.
but, When you turn off the app, need to auth again in web site.
i want auth only first time.
is it possible?
// mycode
get _SCOPES => [CalendarApi.CalendarScope];
await clientViaUserConsent(_clientID, _SCOPES, prompt)
.then((AuthClient client) async {
CalendarClient.calendar = CalendarApi(client);
calendarId = await CalendarClient.calendar.calendarList
.list()
.then((value) => value.items[0].id);
});
void saveData(AccessCredentials credentials) {
GetStorage().write(credetialKey, {
"accessTokenData": credentials.accessToken.data,
"accessTokenExpiry": credentials.accessToken.expiry.toString(),
"refreshToken": credentials.refreshToken,
"scopes": credentials.scopes,
"idToken": credentials.idToken
});
}
AccessCredentials getCredetial() {
try {
var map = GetStorage().read(credetialKey);
return AccessCredentials(
AccessToken("Bearer", map["accessTokenData"] as String,
DateTime.parse(map["accessTokenExpiry"])),
map["refreshToken"],
map["scopes"].cast<String>(),
idToken: map["idToken"] as String);
} catch (e) {
return null;
}
}
Client cli = Client();
var c = await refreshCredentials(_clientID, getCredetial(), cli)
.catchError((e) {
print(e);
});
authenticatedClient(cli, c);
error :
DetailedApiRequestError(status: 401, message: Request is missing required authentication credential. Expected OAuth 2 access tok
You can save user session using for example sharedPreferences. Each time the user launch the app your must first check if the session is saved so you can skip the auth process, otherwise you initiate the authentication
i solved it.
save AccessCredentials,
and use autoRefreshingClient;
Client cli = Client();
var c = await refreshCredentials(_clientID, getCredetial(), cli)
.catchError((e) {
print(e);
});
cli = autoRefreshingClient(_clientID, c, cli);