How to pass an image url to firebase Firestore? - firebase

I am able to pass the name, address, password, and email, but the url is "", how can I pass the image url next to the email and address data? If anyone can help, I would appreciate it very much !! I have a class called User Model and a SignUp.
String userImageUrl = "";
static final String userAvatarUrl = 'url';
final picker = ImagePicker();
PickedFile _imageFile;
if (_formkey.currentState.validate()) {
Map<String, dynamic> userData = {
// "uid": model.firebaseUser.uid,
"name": _nameController.text,
"email": _emailController.text,
"address": _addressController.text,
"url": userImageUrl,
};
model.signUp(
userData: userData,
pass: _passController.text,
onSucess: _onSucess,
onFail: _onFail,
);
}
uploadAndSaveImage();
uploadToStorage();
Future uploadToStorage() async {
showDialog(
context: context,
builder: (c) {
return LoadingAlertDialog(
message: "Autentificando, Por favor espere...",
);
});
String imageFileName = DateTime.now().millisecondsSinceEpoch.toString();
Reference reference = FirebaseStorage.instance.ref().child(imageFileName);
UploadTask task = reference.putFile(File(_imageFile.path));
await (await task).ref.getDownloadURL().then((urlImage) {
urlImage = userImageUrl;
class UserModel extends Model {
Future<Null> _saveUserData(Map<String, dynamic> userData) async {
this.userData = userData;
await FirebaseFirestore.instance
.collection('users')
.doc(firebaseUser.uid)
.set(userData);
}
}

Related

A document path must be a non-empty string, Flutter - Firebase error?

I have some mistakes with flutter and firebase, if someone can help would be great here is my auth controller
class AuthController extends GetxController {
final FirebaseAuth auth = FirebaseAuth.instance;
final Rxn<User> _firebaseUser = Rxn<User>();
Rx<XFile>? _pickedImage;
XFile? get profilePhoto => _pickedImage?.value;
// final user = FirebaseAuth.instance.currentUser.obs;
Rxn<User> get user => _firebaseUser;
// final user = FirebaseAuth.instance.currentUser;
#override
onInit() {
_firebaseUser.bindStream(auth.authStateChanges());
super.onInit();
}
// void register(
// String name, String email, String password, XFile? image) async {
// try {
// UserCredential _authResult = await auth.createUserWithEmailAndPassword(
// email: email.trim(), password: password);
// //create user in database.dart
// String downloadUrl = await uploadToStorage(image!);
// UserModel _user = UserModel(
// id: _authResult.user?.uid,
// name: name,
// email: _authResult.user?.email,
// profilePic: downloadUrl,
// );
// if (await Database().createNewUser(_user)) {
// Get.find<UserController>().user = _user;
// }
// } catch (e) {
// Get.snackbar(
// "Error creating Account",
// e.toString(),
// snackPosition: SnackPosition.BOTTOM,
// );
// }
// }
void register(
String name, String email, String password, XFile? image) async {
try {
if (name.isNotEmpty &&
email.isNotEmpty &&
password.isNotEmpty &&
image != null) {
// save out user to our ath and firebase firestore
UserCredential _authResult = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
String downloadUrl = await uploadToStorage(image);
UserModel _user = UserModel(
id: _authResult.user?.uid,
name: name,
email: _authResult.user?.email,
profilePic: downloadUrl,
);
if (await Database().createNewUser(_user)) {
Get.find<UserController>().user = _user;
} else {
Get.snackbar(
'Error Creating Account',
'Please enter all the fields',
);
}
}
} catch (e) {
Get.snackbar(
'Error Creating Account',
e.toString(),
);
}
}
void login(String email, password) async {
try {
UserCredential _authResult = await auth.signInWithEmailAndPassword(
email: email.trim(), password: password);
Get.find<UserController>().user =
await Database().getUser(_authResult.user?.uid ?? '');
} catch (e) {
Get.snackbar("About User", "User message",
snackPosition: SnackPosition.BOTTOM,
titleText: Text("Acount creation failed"),
messageText:
Text(e.toString(), style: TextStyle(color: Colors.white)));
}
}
Future<void> signOut() async {
await auth.signOut();
Get.find<UserController>().clear();
}
Future pickImage() async {
print("call on click add photo icon");
final ImagePicker _picker = ImagePicker();
final XFile? pickedImage =
await _picker.pickImage(source: ImageSource.gallery);
print('picked image filled with image from gallery'); //This doesnt print at
if (pickedImage != null) {
Get.snackbar('Profile Picture',
'You have successfully selected your profile picture!');
// print(pickedImage.path);
}
_pickedImage = Rx<XFile>(pickedImage!);
// print(_pickedImage);
// print(profilePhoto);
}
// upload to firebase storage
Future<String> uploadToStorage(XFile? image) async {
Reference ref = FirebaseStorage.instance
.ref('')
.child('profilePics')
.child(auth.currentUser!.uid);
// print(ref);
UploadTask uploadTask = ref.putFile(File(image?.path ?? 'idemo'));
print(uploadTask);
// TaskSnapshot snap = await uploadTask;
String downloadUrl = await (await uploadTask).ref.getDownloadURL();
print(downloadUrl);
return downloadUrl;
}
}
Here is my function to createNewUser
class Database {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<bool> createNewUser(UserModel user) async {
try {
await _firestore.collection("users").doc(user.id).set({
"name": user.name,
"email": user.email,
"profilePhoto": user.profilePic
});
return true;
} catch (e) {
print(e);
return false;
}
}
Here is HomeController
class HomeController extends GetxController {
final Rxn<List<TodoModel>> todoList = Rxn<List<TodoModel>>([]);
var selectedDate = DateTime.now().obs;
List<TodoModel>? get todos => todoList.value;
#override
void onInit() {
super.onInit();
String? uid = Get.find<AuthController>().auth.currentUser?.uid ?? '';
print(uid);
todoList.bindStream(Database().todoStream(uid));
}
chooseDate() async {
DateTime? pickedDate = await showDatePicker(
context: Get.context!,
initialDate: selectedDate.value,
firstDate: DateTime(2000),
lastDate: DateTime(2024),
//initialEntryMode: DatePickerEntryMode.input,
// initialDatePickerMode: DatePickerMode.year,
);
if (pickedDate != null && pickedDate != selectedDate.value) {
selectedDate.value = pickedDate;
}
}
}
and here is View page
GetX<HomeController>(
init: Get.put<HomeController>(HomeController()),
builder: (HomeController todoController) {
if (todoController.todos != null) {
// print(todoController.todos?.done ?? false);
return Expanded(
child: ListView.builder(
itemCount: todoController.todos?.length,
itemBuilder: (_, index) {
return TodoCard(
uid: controller.user.value?.uid ?? '',
todo: todoController.todos![index],
);
},
),
);
} else {
return Text("loading...");
}
},
),
So, I have an error when I register a new user I got this error:
The following assertion was thrown building Builder(dirty):
a document path must be a non-empty string
Failed assertion: line 116 pos 14: ‘path.isNotEmpty’
And here is output from terminal:
The relevant error-causing widget was
GetMaterialApp
lib/main.dart:23
When the exception was thrown, this was the stack
#2 _JsonCollectionReference.doc
#3 Database.todoStream
#4 HomeController.onInit
#5 GetLifeCycleBase._onStart
#6 InternalFinalCallback.call
#7 GetInstance._startController
#8 GetInstance._initDependencies
#9 GetInstance.find
#10 GetInstance.put
#11 Inst.put
So a problem is with this path, and when I reload from the visual studio I god the right user with the right data. So the problem is when I register a user for the first time.
It looks like uid is empty, which you should also be able to see from looking up print(uid); in your output.
When your application or web page loads, Firebase automatically tries to restore the previously signed in user from its local state. This requires that it makes a call to the server however (for example to check if the account has been disabled) and while that call is going on, your main code continues to execute and the currentUser variable is going to be null.
Your code needs to take this into account. The easiest way to do this is to not depend on currentUser, but instead to use an reactively respond to changes in the authentication state as shown in the first example in the documentation on getting the current user:
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user != null) {
print(user.uid);
}
});
The authStateChange method here returns a stream that fires an event whenever the authentication state changes, so when the user signs in or signs out. The common way to use this stream is to either set the user to the state of your widget, or to use the stream directly in a StreamBuilder.

Flutter: _CastError (type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast)

When I create a new user the error (_CastError (type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast)) apears at User.fromSnap ...as Map<stringm,dynamic> and firebase creates the user auth but not the user data
Can you help me to add array of array of objects to firebase?
Thanks!
user.dart
class User {
final String uid;
final String name;
final List<Game> game;
User(
{required this.uid,
required this.name,
required this.game});
factory User.fromSnap(DocumentSnapshot snap) {
var snapShot = snap.data() as Map<String, dynamic>;
return User(
uid: snapShot['uid'],
name: snapShot['name'],
game: snapShot['game']);
}
Map<String, dynamic> toJson() => {
'uid': uid,
'name': name,
'game': game,
};
}
class Game{
String rolName;
bool alive;
Game({required this.rolName, required this.alive});
factory Game.fromSnap(Map<String, dynamic> snap) {
return Game(rolName: snap['rolName'], alive: snap['alive']);
}
}
auth.dart
class AuthMethods with ChangeNotifier {
...
Future<String> singUpUser(
{required String email,
required String password,
required String namee}) async {
String res = 'Error';
try {
if (email.isNotEmpty ||
password.isNotEmpty ||
name.isNotEmpty ) {
UserCredential cred = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
model.User _user = model.User(
uid: cred.user!.uid,
name: name,
game: [model.Game(rolName: 'default', alive: false)]);
await _firestore
.collection("users")
.doc(cred.user!.uid)
.set(_user.toJson());
res = 'success';
} else {
res = "Please enter all the fields";
}
} catch (err) {
res = err.toString();
}
return res;
}
Your factory looks right. But you're sending it nothing...the snap is null is what that error is telling you.

How to match Firebase User UID with Firestore Doc ID - Flutter

I am new to flutter. So Please kindly bear with me.
I am creating a Real Estate App using Firebase and Provider.
I have two root Collections (1) "users" and (2) "properties"
I would like to achieve one specific task.
Although it seems like a simple task, yet I am still unable to solve it.
The task is to store Firebase User UID as Firestore Document ID of the rool Collection called "users" when the user sign up.
The problem I am having is the Firestore Document ID is automatically generated and its not Firebase User UID. Plus the field for userId appears null in Firestore.
Please see the screenshot of my database here
Thank you for your attention and time.
Here is my user_model.dart
class NayyaaUser {
String? uid;
String name;
String email;
String? phone;
NayyaaUser({this.uid, required this.name, required this.email, this.phone});
//send data to Firestore
Map<String, dynamic> toMap() {
return {
'userId': uid,
'userName': name,
'userEmail': email,
'userPhone': phone,
};
}
//draw data from firestore
factory NayyaaUser.fromFirestore(Map<String, dynamic> firestore) =>
NayyaaUser(
uid: firestore['userId'],
email: firestore['userEmail'] ?? " ",
name: firestore['userName'] ?? " ",
phone: firestore['userPhone'] ?? " ",
);
}
Here is my user_provider.dart
class UserProvider extends ChangeNotifier {
final firestoreService = FirestoreService();
final authService = AuthService();
String? _userId;
String? _name;
String? _email;
String? _phone;
//getters
String? get userId => _userId;
String? get name => _name;
String? get email => _email;
String? get phone => _phone;
//setters
changeName(String value) {
_name = value;
notifyListeners();
}
changeEmail(String value) {
_email = value;
notifyListeners();
}
changePhone(String value) {
_phone = value;
notifyListeners();
}
saveUserProfile() {
if (_userId == null) {
var updateUserProfile = NayyaaUser(
// userId: _userId,
uid: _userId,
name: name ?? '',
email: email ?? '',
phone: phone ?? '');
firestoreService.saveUserDataToFirestore(updateUserProfile);
} else {
var newUserProfile = NayyaaUser(
// userId: _userId,
uid: _userId,
name: name ?? '',
email: email ?? '',
phone: phone ?? '');
firestoreService.saveUserDataToFirestore(newUserProfile);
}
}
}
Here is auth_service.dart
class AuthService {
final FirebaseAuth _authInstance = FirebaseAuth.instance;
//create user obj based on "User" from Firebase
NayyaaUser? _userFromFirebase(User? user) {
return user != null
? NayyaaUser(
uid: user.uid,
name: '',
email: '',
phone: '',
)
: null;
}
// auth change user stream
Stream<NayyaaUser?> get userAuthStatus {
return _authInstance.authStateChanges().map(_userFromFirebase);
}
// sign in with email + password
Future signIn(String email, String password) async {
try {
UserCredential userAuthResult = await _authInstance
.signInWithEmailAndPassword(email: email, password: password);
User? user = userAuthResult.user;
return _userFromFirebase(user!);
} catch (e) {
// ignore: avoid_print
print(e.toString());
return null;
}
}
Future signUp(String email, String password) async {
try {
UserCredential userAuthResult = await _authInstance
.createUserWithEmailAndPassword(email: email, password: password);
User? user = userAuthResult.user;
return _userFromFirebase(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _authInstance.signOut();
} catch (e) {
// ignore: avoid_print
print(e.toString());
return null;
}
}
}
Here is firestore_service.dart
class FirestoreService {
final CollectionReference _userRef =
FirebaseFirestore.instance.collection('users');
final CollectionReference _propertyRef =
FirebaseFirestore.instance.collection('properties');
//add or update user to firestore
Future<void> saveUserDataToFirestore(NayyaaUser nayyaaUserData) {
return _userRef.doc(nayyaaUserData.uid).set(nayyaaUserData.toMap());
}
// fetch user data from firestore
Stream<List<NayyaaUser>> getNayyaaUser() {
return _userRef.snapshots().map((snapshot) => snapshot.docs
.map((document) =>
NayyaaUser.fromFirestore(document.data() as Map<String, dynamic>))
.toList());
}
}
After login/signup successfully you can get user id from FirebaseAuth.instance.currentUser?.uid

The method 'document' isn't defined for the type 'CollectionReference'. Flutter/Firebase

The method 'document' isn't defined for the type 'CollectionReference'.
Try correcting the name to the name of an existing method, or defining a method named 'document'.
I am getting this error in my project. Can you help me?
My Code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:crypto_app/models/users.dart';
class FireStoreService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final DateTime time = DateTime.now();
Future<void> createUser({id, mail, userName, photoUrl = ""}) async {
await _firestore.collection("users").doc(id).set({
"userName": userName,
"mail": mail,
"photoUrl": photoUrl,
"about": "",
"createTime": time
});
}
Future<Users> bringUser(id) async {
DocumentSnapshot doc = await _firestore.collection("users").doc(id).get();
if (doc.exists) {
Users users = Users.dokumandanUret(doc);
return users;
}
return null;
}
void userUpdate({String userId, String userName, String photoUrl = ""}) {
_firestore
.collection("users")
.document(userId)
.updateData({"userName": userName, "photoUrl": photoUrl});
}
}
CollectionReference in cloud_firestore for flutter/dart does not have a document(..) method. It is called doc(..) instead. https://pub.dev/documentation/cloud_firestore/latest/cloud_firestore/CollectionReference/doc.html

flutter firebase auto refresh user session with refreshToken

I want user in my app to stay logged in. I'm using the firebase authentification with IDToken which lasts for 1hour until it expires. I want to auto refresh the session everytime if it is going to expire.
what Ive read so far here https://firebase.google.com/docs/reference/rest/auth/#section-refresh-token it should be somehow possible with https://securetoken.googleapis.com/v1/token?key=[API_KEY]
This is my full code for authentification right now (flutter)
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../provider/http_exception.dart';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
class Auth with ChangeNotifier {
String _token;
DateTime _expiryDate;
String _userId;
Timer _authTimer;
bool wasLoggedOut = false;
bool onBoarding = false;
Future<void> createUser(String email, String firstName, String lastName) async {
final url = 'https://test45.firebaseio.com/users/$userId.json?auth=$token';
final response = await http.put(url, body: json.encode({
'userEmail': email,
'userIsArtist': false,
'userFirstName': firstName,
'userLastName': lastName,
}));
print('post ist done');
print(json.decode(response.body));
}
bool get isAuth {
return token != null;
}
String get userId {
return _userId;
}
String get token {
if (_expiryDate != null &&
_expiryDate.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
Future<void> authenticate(
String email, String password, String urlSegement) async {
final url = 'https://identitytoolkit.googleapis.com/v1/accounts:$urlSegement?key=AIzaSyD8pb3M325252dfsDC-4535dfd';
try {
final response = await http.post(url,
body: json.encode({
'email': email,
'password': password,
'returnSecureToken': true,
}));
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now().add(Duration(seconds: int.parse(responseData['expiresIn'])));
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate.toIso8601String(),
});
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return authenticate(email, password, 'signUp');
}
Future<void> signin(String email, String password) async {
return authenticate(email, password, 'signInWithPassword');
}
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if(!prefs.containsKey('userData')){
return false;
}
final extractedUserData = json.decode(prefs.getString('userData')) as Map<String, Object>;
final expiryDate = DateTime.parse(extractedUserData['expiryDate']);
if(expiryDate.isBefore(DateTime.now())) {
return false;
}
_token = extractedUserData['token'];
_userId = extractedUserData['userId'];
_expiryDate = expiryDate;
notifyListeners();
_autoLogout();
return true;
}
Future<void> logout() async {
_token = null;
_userId = null;
_expiryDate = null;
if(_authTimer != null){
_authTimer.cancel();
_authTimer = null;
}
notifyListeners();
final prefs = await SharedPreferences.getInstance();
prefs.remove('userData');
}
void _autoLogout() {
if(_authTimer != null) {
_authTimer.cancel();
}
final timetoExpiry = _expiryDate.difference(DateTime.now()).inSeconds;
_authTimer = Timer(Duration(seconds: timetoExpiry), logout);
}
}
how to modify my auth.dart to achieve the auto refreshing?
EDIT:
As mentioned in the comments, im working with providers where I have the following functions to retrieve the token:
update(String token, id, List<items> itemsList) {
authToken = token;
userId = id;
}
also in every of my API calls im using the auth parameter already:
var url = 'https://test45.firebaseio.com/folder/$inside/$ym.json?auth=$authToken';
I just need somebody who can show me how to modify my code with the refresh token.
Thanks in advance!
EDIT:
I tried to implement it, but im getting an infinite loop, please help:
String get token {
if (_expiryDate != null &&
_expiryDate.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
refreshSession();
}
Future<void> refreshSession() async {
final url = 'https://securetoken.googleapis.com/v1/token?key=5437fdjskfsdk38438?grant_type=refresh_token?auth=$token';
try {
final response = await http.post(url,
body: json.encode({
'token_type': 'Bearer',
}));
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['id_token'];
_userId = responseData['user_id'];
_expiryDate = DateTime.now().add(Duration(seconds: int.parse(responseData['expires_in'])));
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate.toIso8601String(),
});
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
I edited your refresh_token() function.
Firstly, you should use your web api key on your firebase project with the link. You should also save the refresh token. And if you post like this, it will work. If don't work, try without json.encode() function on your body as I commit.
Future<void> refreshSession() async {
final url =
'https://securetoken.googleapis.com/v1/token?key=$WEB_API_KEY';
//$WEB_API_KEY=> You should write your web api key on your firebase project.
try {
final response = await http.post(
url,
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: json.encode({
'grant_type': 'refresh_token',
'refresh_token': '[REFRESH_TOKEN]', // Your refresh token.
}),
// Or try without json.encode.
// Like this:
// body: {
// 'grant_type': 'refresh_token',
// 'refresh_token': '[REFRESH_TOKEN]',
// },
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['id_token'];
_refresh_token = responseData['refresh_token']; // Also save your refresh token
_userId = responseData['user_id'];
_expiryDate = DateTime.now()
.add(Duration(seconds: int.parse(responseData['expires_in'])));
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'token': _token,
'refresh_token': _refresh_token,
'userId': _userId,
'expiryDate': _expiryDate.toIso8601String(),
});
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
This is your full auth.dart file which I edited.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../provider/http_exception.dart';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
class Auth with ChangeNotifier {
String _token;
String _refresh_token;
DateTime _expiryDate;
String _userId;
Timer _authTimer;
bool wasLoggedOut = false;
bool onBoarding = false;
Future<void> createUser(String email, String firstName, String lastName) async {
final url = 'https://test45.firebaseio.com/users/$userId.json?auth=$token';
final response = await http.put(url, body: json.encode({
'userEmail': email,
'userIsArtist': false,
'userFirstName': firstName,
'userLastName': lastName,
}));
print('post ist done');
print(json.decode(response.body));
}
bool get isAuth {
return token != null;
}
String get userId {
return _userId;
}
String get token {
if (_expiryDate != null &&
_expiryDate.isAfter(DateTime.now()) &&
_token != null && _refresh_token!=null) {
return _token;
}
refreshSession();
return null;
}
Future<void> authenticate(
String email, String password, String urlSegement) async {
final url = 'https://identitytoolkit.googleapis.com/v1/accounts:$urlSegement?key=AIzaSyD8pb3M325252dfsDC-4535dfd';
try {
final response = await http.post(url,
body: json.encode({
'email': email,
'password': password,
'returnSecureToken': true,
}));
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['idToken'];
_refresh_token = responseData['refreshToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now().add(Duration(seconds: int.parse(responseData['expiresIn'])));
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'token': _token,
'refresh_token': _refresh_token,
'userId': _userId,
'expiryDate': _expiryDate.toIso8601String(),
});
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return authenticate(email, password, 'signUp');
}
Future<void> signin(String email, String password) async {
return authenticate(email, password, 'signInWithPassword');
}
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if(!prefs.containsKey('userData')){
return false;
}
final extractedUserData = json.decode(prefs.getString('userData')) as Map<String, Object>;
final expiryDate = DateTime.parse(extractedUserData['expiryDate']);
if(expiryDate.isBefore(DateTime.now())) {
return false;
}
_token = extractedUserData['token'];
_refresh_token = extractedUserData['refresh_token'];
_userId = extractedUserData['userId'];
_expiryDate = expiryDate;
notifyListeners();
_autoLogout();
return true;
}
Future<void> logout() async {
_token = null;
_refresh_token = null;
_userId = null;
_expiryDate = null;
if(_authTimer != null){
_authTimer.cancel();
_authTimer = null;
}
notifyListeners();
final prefs = await SharedPreferences.getInstance();
prefs.remove('userData');
}
void _autoLogout() {
if(_authTimer != null) {
_authTimer.cancel();
}
final timetoExpiry = _expiryDate.difference(DateTime.now()).inSeconds;
_authTimer = Timer(Duration(seconds: timetoExpiry), logout);
}
Future<void> refreshSession() async {
final url =
'https://securetoken.googleapis.com/v1/token?key=$WEB_API_KEY';
//$WEB_API_KEY=> You should write your web api key on your firebase project.
try {
final response = await http.post(
url,
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: json.encode({
'grant_type': 'refresh_token',
'refresh_token': '[REFRESH_TOKEN]', // Your refresh token.
}),
// Or try without json.encode.
// Like this:
// body: {
// 'grant_type': 'refresh_token',
// 'refresh_token': '[REFRESH_TOKEN]',
// },
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
_token = responseData['id_token'];
_refresh_token = responseData['refresh_token']; // Also save your refresh token
_userId = responseData['user_id'];
_expiryDate = DateTime.now()
.add(Duration(seconds: int.parse(responseData['expires_in'])));
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'token': _token,
'refresh_token': _refresh_token,
'userId': _userId,
'expiryDate': _expiryDate.toIso8601String(),
});
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
}
You need to save the refresh token.
Follow this topic to refresh your IDToken using the refresh token: https://firebase.google.com/docs/reference/rest/auth#section-refresh-token
When making any calls to the API, use a function to retrieve the IDToken. This function must check if the current IDToken is still valid and, if not, ask for a new one (using the link provided).
I think the Dio library is right for you
dio = Dio();
dio.options.baseUrl = URL_API_PROD;
dio.interceptors.add(InterceptorsWrapper(
onRequest: (Options option) async{
//getToken() : you can check token expires and renew in this function
await getToken().then((result) {
token = result;
});
option.headers = {
"Authorization": "Bearer $token"
};
}
));
Response response = await dio.get('/api/users');
body expects string...Hence change body in refreshSession() to body: 'grant_type=refresh_token&refresh_token=[YOUR REFRESH TOKEN]',.
You need to load 'refreshToken' from SharedPreferences before sending http.post request.

Resources