OAuth Acces Token Verification in node.js - node.js

I am working on a flutter app and would want to use facebook and google oauths to authenticate my users. Here is the code on the client side which works perfectly.
import 'package:flutter/material.dart';
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
import 'package:http/http.dart' as http;
import 'dart:convert' as JSON;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isLoggedIn = false;
Map userProfile;
final facebookLogin = FacebookLogin();
_loginWithFB() async {
final result = await facebookLogin.logIn(['email']);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
final token = result.accessToken.token;
final graphResponse = await http.get(
'https://graph.facebook.com/v2.12/me?fields=name,picture,email&access_token=${token}');
final profile = JSON.jsonDecode(graphResponse.body);
print(profile);
setState(() {
userProfile = profile;
isLoggedIn = true;
});
break;
case FacebookLoginStatus.cancelledByUser:
setState(() => isLoggedIn = false);
break;
case FacebookLoginStatus.error:
setState(() => isLoggedIn = false);
break;
}
}
_logoutWithFB() {
facebookLogin.logOut().then((value) => setState(() => isLoggedIn = false));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: isLoggedIn
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.network(
"http://placehold.it/50x50",
height: 50.0,
width: 50.0,
),
SizedBox(
height: 50.0,
),
OutlineButton(
onPressed: _logoutWithFB,
child: Text('Logout'),
),
],
)
: OutlineButton(
onPressed: _loginWithFB,
child: Text('Facebook login'),
color: Colors.blueAccent,
),
),
);
}
}
The logic I want to use is for sign in, the user sign up with facebook or google, I get some basic info and ask the user to add some further information in another screen, then on submission the user info and the token are sent to the backend (which is a node.js api).\
On the back I want to verify the token received from the front end with facebook or google and if the profile id match the one received the user info received from the front end is saved, then a JWT would be created and sent to the front end.
My challenge now is how do I verify the oauth token on the node.js side.

User -> SignIn Facebook -> Token generated -> Token Sent to Backend -> Middleware Nodejs -> check user_id exist -> generate JWT -> sendBackTo clientSide.
It's very simple you have to create a middleware function in your back-end nodejs in this case.
const express = require("express");
const app = express();
//function that return JWT token
String check_user_id(req,res,next) async
{
var uid = req.params.uid
//Query database check if userIdexist or not
check_db(uid)
//if it exist
next();
return GenerateJwt(userId)
else
{
//Signup the userid
SignUp(userId);
//generateJWT
next();
return GenerateJwt(userId);
}
}
app.get('/check_uid/:uid',check_user_id,(res,req,next) =>
{
res.send({'message':'verified'});
}

Related

How to change AppBar's automaticallyImplyLeading property via a Consumer

As someone new to Flutter/Dart, I have a simplistic proof-of-concept web app (code provided below) where I've genuinely put the effort in to reading & prototyping but cannot quite get the code finished.
The app is a test of named routes. FirstScreen uses an ElevatedButton to jump to SecondScreen. SecondScreen can only return to FirstScreen via the Back arrow in SecondScreen's AppBar, but I also want the ability to dynamically hide that Back arrow if the app is started from SecondScreen, or enable it if the app is started from FirstScreen. Why ? Because the idea is to provide the option to run SecondScreen in a kiosk mode where the user's navigation is restricted to that one route of the app.
I designed the code to use a ChangeNotifier/Consumer approach using Flutter's "provider" package. The state is provided by the routedViaHome boolean (default is false) in RouteMonitor. The only time the boolean should be set true is if the app starts at FirstScreen and the user clicks the ElevatedButton to go to SecondScreen; that change is observed by SecondScreen and should be used to dynamically set its own AppBar 'automaticallyImplyLeading' property.
My question is this: the Consumer is correctly displaying the Text widget, but how do I ALSO get it to update the automaticallyImplyLeading property ? What am I missing please and/or have I needlessly complicated this ?
Thank you !
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => RouteMonitor(),
child: const MyApp(),
)
);
}
class RouteMonitor with ChangeNotifier {
bool routedViaHome = false;
void routeViaHome() {
routedViaHome = true;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Named Routes Demo',
initialRoute: '/',
routes: {
'/': (context) => const FirstScreen(),
'/second': (context) => const SecondScreen(),
},
);
}
}
class FirstScreen extends StatelessWidget {
const FirstScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('First Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Provider.of<RouteMonitor>(context, listen: false).routeViaHome();
Navigator.pushNamed(context, '/second');
//Navigator.pushReplacementNamed(context, '/second');
},
child: const Text('Launch screen'),
),
),
);
}
}
class SecondScreen extends StatelessWidget {
const SecondScreen({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second Screen'),
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('This is static data but no navigation'),
Consumer<RouteMonitor>(
builder: (context, routemonitor, child) => Text(
'${routemonitor.routedViaHome}',
style: Theme.of(context).textTheme.headlineMedium,
),
),
],
),
),
);
}
}

(Flutter) How can I identify which ListTile in my ListView the user clicked the PopupMenuItem?

I have a ListView which holds ListTiles. Each tile represents a user of my users array. The trailing of a tile is a PopupMenuButton. When the user clicks on one PopupMenuItem, a function shall be called. So far so good. In the "onSelected" I would like to pass data of the corresponding user to a function.
Could anybody please give me a hint, how I should change the code to be able to do so?
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:cloud_functions/cloud_functions.dart';
import 'package:flutter/material.dart';
class UserListMobilePortrait extends StatelessWidget {
final List<QueryDocumentSnapshot> users;
const UserListMobilePortrait({
Key key,
this.users,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final HttpsCallable setRoleCallable = CloudFunctions.instance
.getHttpsCallable(functionName: 'setRoles')
..timeout = const Duration(seconds: 10);
final button = new PopupMenuButton(
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: const Text('Make Admin'), value: 'admin'),
new PopupMenuItem<String>(
child: const Text('Make Editor'), value: 'editor'),
],
onSelected: (selectedItem) async {
try {
final HttpsCallableResult result = await setRoleCallable.call(
<String, dynamic>{
//'user' shall represent the user of the clicked ListTile, but how to pass it?
'email': user.data()['email'],
'role': selectedItem,
'permission': 'grant'
},
);
print(result.data);
} on CloudFunctionsException catch (e) {
print('caught firebase functions exception');
print(e.code);
print(e.message);
print(e.details);
} catch (e) {
print('caught generic exception');
print(e);
}
});
return ListView(
children: users
.map((user) => ListTile(
title: Text(
(user.data()['email'] != null) ? user.data()['email'] : ""),
subtitle: Row(
children: [
Text((user.data()['displayName'] != null)
? user.data()['displayName']
: ""),
Container(
width: 6,
),
user.data()['isAdmin'] == true
? Chip(
label: Text('admin'),
backgroundColor: Colors.orange[600],
shadowColor: Colors.orange[900],
)
: Text(''),
Container(
width: 6,
),
user.data()['isEditor'] == true
? Chip(
label: Text('editor'),
backgroundColor: Colors.blue[600],
shadowColor: Colors.blue[900],
)
: Text(''),
],
),
trailing: button,
))
.toList(),
);
}
}
understanding your problem a simple workaround will be to use a Listview Builder(And also using a ListView Builder will optmize the app for speed)
const List = ["Hello", "World", "Temp"]
ListView.builder(
itemBuilder: (context, index) {
//return (Your widget [a list tile preferably and use onTap(and access the index
in the function)])
return(ListTile(onTap:(){
print(List[index]);
//you can access the index and use the main list to get its following data
};
};
This will workout :)
My solution was moving the former final button to its own class. So I can pass the data to the constructor.
UserPopupMenuButton
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:cloud_functions/cloud_functions.dart';
import 'package:flutter/material.dart';
class UserPopupMenuButton extends StatelessWidget {
final QueryDocumentSnapshot user;
const UserPopupMenuButton({
Key key,
this.user,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final HttpsCallable setRoleCallable = CloudFunctions.instance
.getHttpsCallable(functionName: 'setRoles')
..timeout = const Duration(seconds: 10);
return PopupMenuButton(
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: const Text('Make Admin'), value: 'admin'),
new PopupMenuItem<String>(
child: const Text('Make Editor'), value: 'editor'),
],
onSelected: (selectedItem) async {
try {
final HttpsCallableResult result = await setRoleCallable.call(
<String, dynamic>{
'email': user.data()['email'],
'role': selectedItem,
'permission': 'grant'
},
);
print(result.data);
} on CloudFunctionsException catch (e) {
print('caught firebase functions exception');
print(e.code);
print(e.message);
print(e.details);
} catch (e) {
print('caught generic exception');
print(e);
}
});
}
}
And using it as the trailing for the ListTile:
trailing: UserPopupMenuButton(user: user),

Flutter reading from file returns Instance of Future<String> instead of the real text in the file

I want to read the data from a .txt file in FLutter, it contains just a number. I use the functions from the official documentations(https://flutter.dev/docs/cookbook/persistence/reading-writing-files), of course modified them a bit to fit in my program:
class _InClassRoomState extends State<InClassRoom> {
#override
var pontsz = readpontok().toString();
void initState() {
super.initState();
}
Future<String> readpontok() async {
try {
final file = await _localFile;
// Read the file.
String contents = await file.readAsString();
return await contents;
} catch (e) {
// If encountering an error, return 0.
return null;
}
}
The respecting part of my widget tree is the body of the Scaffold:
body: Center(
child: Text(
pontsz.toString(),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 50,
color: Colors.black,
),
),
),
But when I run the code it just writes "Instance of Future in the body of the scaffold. Why?
You are passing a Future to the string. you should call readpontok() from initState() and setState pontsz = content
class _InClassRoomState extends State<InClassRoom> {
// create pontsz variable
var pontsz;
#override
void initState() {
super.initState();
// call the function
readpontok();
}
Future readpontok() async {
try {
final file = await _localFile;
// Read the file.
String contents = await file.readAsString();
setState(() {
pontsz = contents;
});
} catch (e) {
// If encountering an error, display Error
setState(() {
pontsz = "Error";
});
}
}
}

How to get the file selected

I am building a flutter web using old version. I am having a FileUploadInputElement. I need to get the file selected from that element.
#override
Widget build(BuildContext context) {
FileUploadInputElement fileUploadInputElement = FileUploadInputElement();
ui.platformViewRegistry.registerViewFactory(
'animation-Image-html', (int viewId) => fileUploadInputElement);
return SizedBox(
child: HtmlElementView(
viewType: 'animation-Image-html',
),
);
}
You can directly use the element.files property to access the files and use the Filreader class from dart:html. I have created an example below to show you how a text file and image can be read. This example is based on FileReader examples in another post.
Accessing the file
Here element is the FileUploadInputElement reference.
element.files[0] or in case of multiple files element.files
Set up your file reader
String option1Text = "Initialized text option1";
Uint8List uploadedImage;
FileUploadInputElement element = FileUploadInputElement()..id = "file_input";
// setup File Reader
FileReader fileReader = FileReader();
Use FileReader to read the file
fileReader.readAsText(element.files[0])
connect the listener for load event
fileReader.onLoad.listen((data) {
setState(() {
option1Text = fileReader.result;
});
});
connect error events
fileReader.onError.listen((fileEvent) {
setState(() {
option1Text = "Some Error occured while reading the file";
});
});
Use Image.memory to show images from byte array.
Image.memory(uploadedImage)
Note: In the following example we choose a file and click the respective button to handle the file reading. But the same can be achieved by connecting the logic in respective events of the FileUploadInputElement element in a similar approach. eg: element.onLoad.listen or element.onError.listen event streams.
Full Example
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'dart:html';
class FileUploadTester extends StatefulWidget {
#override
_FileUploadTesterState createState() => _FileUploadTesterState();
}
class _FileUploadTesterState extends State<FileUploadTester> {
String option1Text = "Initialized text option1";
Uint8List uploadedImage;
FileUploadInputElement element = FileUploadInputElement()..id = "file_input";
// setup File Reader
FileReader fileReader = FileReader();
// reader.onerror = (evt) => print("error ${reader.error.code}");
#override
Widget build(BuildContext context) {
ui.platformViewRegistry.registerViewFactory("add_input", (int viewId) {
return element;
});
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
FlatButton(
color: Colors.indigoAccent,
child: Text('ReadFile'),
onPressed: () {
fileReader.onLoad.listen((data) {
setState(() {
option1Text = fileReader.result;
});
});
fileReader.onError.listen((fileEvent) {
setState(() {
option1Text = "Some Error occured while reading the file";
});
});
fileReader.readAsText(element.files[0]);
},
),
Expanded(
child: Container(
child: Text(option1Text),
),
),
Expanded(child: HtmlElementView(viewType: 'add_input')),
Expanded(
child: uploadedImage == null
? Container(
child: Text('Uploaded image should shwo here.'),
)
: Container(
child: Image.memory(uploadedImage),
),
),
FlatButton(
child: Text('Show Image'),
color: Colors.tealAccent,
onPressed: () {
fileReader.onLoad.listen((data) {
setState(() {
uploadedImage = fileReader.result;
});
});
fileReader.onError.listen((fileEvent) {
setState(() {
option1Text = "Some Error occured while reading the file";
});
});
fileReader.readAsArrayBuffer(element.files[0]);
},
),
],
);
}
}
Below
Image Upload in Flutter Web - Working perfectly fine for me :)
startFilePicker() async {
FileUploadInputElement uploadInput = FileUploadInputElement();
uploadInput.multiple = true;
uploadInput.draggable = true;
uploadInput.click();
uploadInput.onChange.listen((e) {
// read file content as dataURL
final files = uploadInput.files;
print(files);
if (files != null && files.isNotEmpty) {
for (var i = 0; i < files.length; i++) {
FileReader reader = FileReader();
reader.onLoadEnd.listen((e) async {
if (reader.result != null) {
Uint8List? _byteData = reader.result as Uint8List;
// upload the image
}
});
reader.onError.listen((fileEvent) {
Fluttertoast.showToast(
msg: "Some Error occured while reading the file");
});
reader.readAsArrayBuffer(files[i]);
}
} else {
Fluttertoast.showToast(msg: 'Images not selected');
}
});
}

Is there any plugin or way to upload file to server using flutter web?

I want to upload image to the server from flutter web application. Is there any better way of doing that.
I've already tried with couple of plugins.
image-picker, file-picker
But none of them are supported for flutter web.
you can use the FileUploadInputElement class of dart:html.
The first thing to do is to import dart:html.
import 'dart:html';
Implement following code to start a file picker:
_startFilePicker() async {
InputElement uploadInput = FileUploadInputElement();
uploadInput.click();
uploadInput.onChange.listen((e) {
// read file content as dataURL
final files = uploadInput.files;
if (files.length == 1) {
final file = files[0];
final reader = new FileReader();
reader.onLoadEnd.listen((e) {
_handleResult(reader.result);
});
reader.readAsDataUrl(file);
}
});
}
There are plenty options at the moment. There is file_picker, drop_zone and so one.
This example works at the moment for files up to the size of 530MB.
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
VoidCallback openFilePicker = () async {
FilePickerResult? result;
print("pick files");
result = await FilePicker.platform.pickFiles(allowMultiple: true, withReadStream: true, withData: false);
if (result != null) {
print(result.files.first.name);
//---Create http package multipart request object
var request = http.MultipartRequest(
"POST",
Uri.parse("http://127.0.0.1:8000/backend/api/upload"),
);
List<PlatformFile>? files = result.files;
if (files != null) {
print("adding files selected with file picker");
for (PlatformFile file in files) {
//-----add selected file with request
request.files.add(http.MultipartFile(
"Your parameter name on server side",
file.readStream!,
file.size,
filename: file.name));
}
}
//-------Send request
var resp = await request.send();
//------Read response
String result2 = await resp.stream.bytesToString();
//-------Your response
print(result2);
}
};
TextButton selectAndSend = TextButton(onPressed: openFilePicker, child: Text("Selet and send"));
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Flutter bug example')),
body: selectAndSend
)
);
}
}

Resources