How to get AutoRefreshingAuthClient from AuthClient without any service account (Google Auth) - flutter

I need an AutoRefreshingAuthClient to use gsheet to play with authenticated users Google Sheet. I can get AuthClient using google_sign_in package.
So, How can I get AutoRefreshingAuthClient from AuthClient in a flutter application without any service account?
The reason I don't want to use a Service Account is,
If I use a Service Account, all files are saved into this Service Account. But, I want to read, write and use Google Sheet from the authenticated user's account.

I ended up using googleapis instead. Seems like gsheets was made to work specifically with Service Accounts so even if you create a valid AutoRefreshingAuthClient it'll check to see if it's a Service Account.
Here's how I did it with the SheetsApi (The GoogleAuthClient class was found after a lot of searching on GitHub and multiple users had the same thing):
import 'package:http/http.dart' as http;
class GoogleAuthClient extends http.BaseClient {
final Map<String, String> _headers;
final http.Client _client = new http.Client();
GoogleAuthClient(this._headers);
Future<http.StreamedResponse> send(http.BaseRequest request) {
return _client.send(request..headers.addAll(_headers));
}
}
final client = GoogleAuthClient((await _googleSignIn.currentUser.authHeaders));
_SheetApi = sheets.SheetsApi(client);
There is as decent amount of overhead on our side with SheetsApi compared to GSheets. Like appending rows or simply naming your Spreadsheet requires more lines of code and/or objects:
// Sheet creation
sheets.Spreadsheet request = sheets.Spreadsheet.fromJson({
'properties': {
'title': "$title",
},
});
sheets.Spreadsheet sh = getSheetApi().spreadsheets.create(request));
// Add first row
List<String> row = [...];
getSheetApi().spreadsheets.values.append(createSheetRows([columns]), sh.spreadsheetId, "Sheet1!$startLetter:$endLetter",
valueInputOption: 'USER_ENTERED');
...
static sheets.ValueRange createSheetRows(List<List<String>> row){
return sheets.ValueRange.fromJson({
"values": row,
"majorDimension": "ROWS"
});
}
static sheets.ValueRange createSheetRow(List<String> row){
return createSheetRows([row]);
}

Related

How to set user Id and propeties in Firebase Analytics - Flutter

Goal : To save user ID and their properties, as he/she interacts with the flutter application.
Problem : Events are getting logged but i cant see user id and properties. I noticed it initially (that user id and properties arre not being logged) while working in debug mode, and then I also waited for 24-48 hours to check in the dashboard but no details for userId.
Documentation link : https://firebase.google.com/docs/analytics/userid#dart
and Yes the properties that I am trying to save in analytics, I have defined them in Custom definitions under User scope.
Code :
import 'package:firebase_analytics/firebase_analytics.dart';
class AnalyticsClass {
static final AnalyticsClass _singleton = AnalyticsClass._internal();
late FirebaseAnalytics fa = FirebaseAnalytics.instance;
factory AnalyticsClass() {
return _singleton;
}
AnalyticsClass._internal();
buttonTap(id, name) async {
await fa.logEvent(name: 'button_tap');
}
setUser(String id, name) async {
await fa.setUserId(id: id);
await fa.setUserProperty(name: 'referral', value: "test new : $name");
}
resetUser() async {
await fa.setUserId(id: null);
await fa.setUserProperty(name: 'referral', value: null);
}
}
If you're using the setUserId() in Firebase, this does not show up in the Analytics reports due to privacy concerns. What you can do is to export your data to BigQuery. This will allow you to query your raw data as well as build custom reports via Data Studio. You may also consider using the User explorer in Google Analytics Dashboard which will help you gain more insight on the behavior of your individual users.

Create USDT Wallet on ERC20 Dart

I want to understand for myself how to generate USDT ERC20 wallet in dart language. I found the web3dart library. But what does it take to generate a koschel using the 12-word phrase provided by the bip39 library? And I don’t understand, is it necessary to write a smart contract? I would like to see a small code example of how to generate a wallet. Many thanks.
Update:
I seem to have managed to generate a wallet. But how to make exactly USDT on ERC20?
var random = Random.secure();
var mnemonic = 'obvious width mechanic wheat cargo toe bike seek spirit jungle enlist thumb';
String mnemonicToSeedHex = bip39.mnemonicToSeedHex(mnemonic);
EthPrivateKey credentials = EthPrivateKey.fromHex(mnemonicToSeedHex);
Wallet wallet = Wallet.createNew(credentials, mnemonic, random);
var address = await credentials.extractAddress();
dev.log(address.hex);
Since USDT is an erc-20 token, you can use the erc-20 abi for contract interactions.
final _erc20ContractAbi = web3.ContractAbi.fromJson(
'[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]',
'Erc20');
Now write a class to interact with each functions in the abi. You need to pass the contract address, web3client (infura or any other) and chainID (1 for ethereum mainnet)
class ERC20 extends web3.GeneratedContract {
ERC20({
required web3.EthereumAddress address,
required web3.Web3Client client,
int? chainId,
}) : super(web3.DeployedContract(_erc20ContractAbi, address), client,
chainId);
Now you can get the balance of your USDT by writing a balanceOf method inside the class like this,
Future<BigInt> balanceOf(
web3.EthereumAddress account, {
web3.BlockNum? atBlock,
}) async {
final function = self.abi.functions[2];
assert(checkSignature(function, '70a08231'));
final params = [account];
final response = await read(function, params, atBlock);
return (response[0] as BigInt);
}
Function to Transafer USDT tokens,
Future<String> transfer(
web3.EthereumAddress recipient,
BigInt amount, {
required web3.Credentials credentials,
web3.Transaction? transaction,
}) async {
final function = self.abi.functions[7];
assert(checkSignature(function, 'a9059cbb'));
final params = [recipient, amount];
return write(credentials, transaction, function, params);
}
Check out my article on Medium , Crypto-wallet app using flutter to get an idea on how to build your own erc-20 token and use flutter mobile application to build a wallet that can transfer the coins.

Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. in flutter with google drive

When I am trying to fetch data from google drive then I am getting these issues.
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: DetailedApiRequestError(status: 403, message: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.)
Fetching Code:
var client = http.Client();
var drive = ga.DriveApi(client);
drive.files.list(spaces: 'gdrv').then((value) {
print('Value = ${value}');
});
Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.
Is the error message you get when you have not sent an authorization header with your request.
Requests to the Google drive api access private user data which means you need to be authenticated in order to access that data.
Your http client appears to be missing all the headers I found this example How to Use the Google Drive API With Flutter Apps it may help.
class GoogleAuthClient extends http.BaseClient {
final Map<String, String> _headers;
final http.Client _client = new http.Client();
GoogleAuthClient(this._headers);
Future<http.StreamedResponse> send(http.BaseRequest request) {
return _client.send(request..headers.addAll(_headers));
}
}

Flutter authentication with email and password without using Firebase

Is it possible to achive authentication with email and password in flutter without using firebase? I have searched around Stackoverflow and internet in general and found nothing about this.
I am creating a simple authentication class this is what I have done at the moment:
class User {
bool isAuthenticated = false;
late String userid;
late String username;
late String email;
late DateTime expireDate; // this variable is used to make the user re-authenticate when today is expireDate
User(bool isAuthenticated, String userid, String username, String email) {
this.isAuthenticated = isAuthenticated;
this.userid = userid;
this.username = username;
this.email = email;
this.expireDate = new DateTime.now().add(new Duration(days: 30));
}
}
class Authentication {
Future<User> signin(String email, String password) {}
void signup(String username, String email, String password) {}
}
EDIT #1: I know how to setup a cookie/token based authentication server I have my own repos on that topic: cookie authentication, token authentication but I don't know how to handle the tokens/cookies in flutter.
This answer is based of #edit1. Since you mentioned that you already know how to set up tokens on the server side you're half way done. Here's a few assumptions I'm making, you already know js/php and worked with JSON output, The database already has a column and table that keeps track of sessions and user_id.
Since you know how Cookies are built this should be relatively easy cause i built it around similar architecture. We has to use the local memory that app's provide access to. There are two packages in flutter that allow u to do this, you can use either:
shared_preferences package link
flutter_secure_storage package link
The main difference is if you want to store 'tokens' or data you want secure you would obviously use flutter_secure_storage. I'm going to use this for code example. And yes the data is saved even after the app is closed.
Setting up Tokens(flutter):
Setting up User Class
When using firebase we generally take for granted the user class that comes with flutter_auth but that is basically what we have to build. A user class with all the data u want to store and then a function called authenticate.
class AppUser{
final _storage = new FlutterSecureStorage();
//below class is mentioned in the next part
AuthApi api = new AuthApi();
//constructor
AppUser(){
//ur data;
};
Future<bool> authenticate(email, password) async {
//this is the api mentioned in next part
http.Response res = await api.login(email, password);
Map<String, dynamic> jsonRes = jsonDecode(res.body);
if (jsonRes["error"]) {
return false;
}
_setToken(jsonRes["token"]);
_setUID(jsonRes["user-id"].toString());
_setAuthState(true);
return true;
}
Future<void> _setToken(String val) async {
//how to write to safe_storage
await _storage.write(key: 'token', value: val);
}
Future<void> _setUID(String val) async {
await _storage.write(key: 'user_id', value: val);
}
//you can stream this or use it in a wrapper to help navigate
Future<bool> isAuthenticated() async {
bool authState = await _getAuthState();
return authState;
}
Future<void> _getAuthState() async {
//how to read from safe_storage u can use the same to read token later just replace 'state' with 'token'
String myState = (await _storage.read(key: 'state')).toString();
//returns boolean true or false
return myState.toLowerCase() == 'true';
}
Future<void> _setAuthState(bool liveAuthState) async {
await _storage.write(key: 'state', value: liveAuthState.toString());
}
}
and assuming ur going to authenticate on a button press so it would look like
onPressed(){
AuthUser user = new AuthUser();
if(user.authenticate(email, password)){
//if logged in. Prolly call Navigator.
}else{
//handle error
}
}
Setting up api calls
Oka so this is calling a Node express API, and the json output looks like
//if successful
{"status":200, "error": false, "token": "sha256token", "user-id": "uid"}
we need to create a class that will give us an output for making this call hence the AuthApi class
class AuthApi {
//this is the login api and it returns the above JSON
Future<http.Response> login(String email, String password){
return http.post(
Uri.parse(ip + '/api/auth/login'),
headers: <String, String>{
'Content-Type': 'application/json',
},
body: jsonEncode(<String, String>{
"email": email,
"password": password,
}),
);
}
}
Thank you for clarifying what u needed, it helped answer better.
You can use Nodejs & express to create your own API and MongoDB or any other DB to act as a persistent DB. I am attaching my github repo link which has minimum code required to setup a email/password auth in mongodb
Github
EDIT :
I have little to no idea about sessions but for tokens there are packages in pub.dev which lets you decode the tokens. jwt-decoder.
You can check the expiry time of the token using this package and for storing them you can use secure_storage
I had a look at your token authentication repo. I would suggest you to verify the token when you get them and not just blindly trust them.
Yes it is Totally possible to create Authentication without Firebase, but it becomes a-lot more difficult and there are multiple solutions.
What firebase provides:
Server space with no down time
Complete set of Api's including authentication with various methods
Strong security(built by google)
Ease of use and setup with great documentation
The reason I bring these up is cause the alternative ur looking for is very difficult for a programer who's relatively new and can feel like you are building multiple applications at a time. It's definitely a learning curve. Also I'm assuming u don't just want local authentication cause thats kinda pointless.
Creating ur own backend involves:
Setting up a server(usually ubuntu)(and either on a raspi or a host like amazon, digital ocean, etc)
Setting up a database with tables(mysql, sql, mongoDB)
Creating communication API's (php, Node.js)
So here's what i'd recommend for getting into backend dev,
use LAMP architecture : Linux, Apache, MySQL, PHP
Setting up Lamp isn't too hard heres a link i followed:
https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-ubuntu-16-04
After u set up ur back end, then u have to create api calls from flutter.
The call (if u created an auth.php where people can login) would look something like:
http://ip:8080/auth.php?email="example#gmail.com"&pass="123456"
I understand why you feel like you didn't find solutions, i was there too but there are tons,LAMP is one of the more easier ones. If u are still interested i'd recommend checking out System Design courses.

Can I update a user document whenever a user updates his authentication profile?

I am working with flutter and I have a AuthenticationProvider. Whenever my user signs in with his phone I update his profile as well. But my problem is that auth users can't be queried. So I read that I should keep a separate user collection. Now my question is, is it possible to update a user document in my user collection whenever a user updates his auth profile? I would like to do this with cloud functions but I noticed that there is only a create and delete? So how can I do this?
This is what I currently have
Authentication Provider
Future<void> _verificationComplete(BuildContext context, AuthCredential authCredential, userInfo.UserInfo userInfo) async {
AuthResult authResult = await FirebaseAuth.instance.signInWithCredential(authCredential);
final userUpdateInfo = UserUpdateInfo();
userUpdateInfo.displayName = userInfo.name;
userUpdateInfo.photoUrl = userInfo.photoUrl;
await authResult.user.updateProfile(userUpdateInfo);
await authResult.user.reload();
user = UserModel.fromFirebase(authResult.user);
_status = AuthenticationStatus.authenticated;
notifyListeners();
}
Cloud function
export const onUserCreated = functions.region('europe-west1').auth.user().onCreate(async user => {
const privateUserData = {
activeGroup: '',
cloudMessagingToken: '',
}
const publicUserData = {
name: '',
photoUrl: '',
}
const promises = [];
promises.push(firestore.collection('users').doc(user.uid).collection('private').doc('data').set(privateUserData));
promises.push(firestore.collection('users').doc(user.uid).collection('public').doc('data').set(publicUserData));
return await Promise.all(promises);
});
There is no Cloud Functions trigger for when a user updates their Firebase Authentication profile. I'd highly recommend filing a feature request for that, as it's much missed.
For now, the closest you can get is with a Cloud Function that you call directly from the application code. The two options there are:
Have your application code call the Firebase Authentication API first, then when that completes, have it call your custom Cloud Function to update the database too.
Have your application code call the Cloud Function immediately, and then have the Cloud Function update both the user profile and the database.
I somehow often do the first one, but see more developers take the second approach. I think their approach is probable simpler, but I just haven't gotten around to it yet. :)