Flutter Request failed Google Pay live mode using Stripe Payment - flutter

Google pay is completely working on Test mode but after set the live secret key in "v1/payment_intents" in this API so it's not working and getting the below error. I'm using the Stripe plugin.
Future<void> startGooglePay() async {
final googlePaySupported = await Stripe.instance.isGooglePaySupported(IsGooglePaySupportedParams(testEnv:
false));
if (googlePaySupported) {
try {
// 1. fetch Intent Client Secret from backend
final response = await fetchPaymentIntentClientSecret();
print(response);
final clientSecret = response['client_secret'];
// 2.present google pay sheet
await Stripe.instance.initGooglePay(GooglePayInitParams( merchantName: "Test Name",
countryCode: 'US',testEnv: false));
await Stripe.instance.presentGooglePay(PresentGooglePayParams(clientSecret: clientSecret,currencyCode: "GBP"),);
await Stripe.instance.initPaymentSheet(paymentSheetParameters: SetupPaymentSheetParameters(
googlePay: PaymentSheetGooglePay(merchantCountryCode: 'US'),
paymentIntentClientSecret: response['client_secret'],
setupIntentClientSecret:response['client_secret'],
customerEphemeralKeySecret: response['client_secret'],
customerId:PLPrefrence.getPrefValue(key: PLPrefrence.user_code).toString()
));
await Stripe.instance.retrievePaymentIntent(response['client_secret']).then((value){
print(value.id);
print(value.status);
print(value.confirmationMethod.name);
});
} catch (e) {
print('ErrorStripePrint : ${e}');
errorDialog(errorMessage: "$e");
}
} else {
errorDialog(errorMessage: "Google pay is not supported on this device");
}
}
Now here is the API call for payment_intents API
Future<Map<String, dynamic>> fetchPaymentIntentClientSecret() async {
final url = Uri.parse('https://api.stripe.com/v1/payment_intents');
Map<String, dynamic> body = {
'amount':calculateAmount(amount: _plController.isUseWalletbalance.value ?
_plController.processedAmount.value : widget.grandTotal.toString()).toString(),
'currency': "GBP",
'payment_method_types[]': 'card',
};
final response = await http.post(
url,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ${PLKeys.stripeSK_Live}',
},
body: body,
);
return json.decode(response.body);
}
if I set the testEnv true and test secret key in so it's working but set testEnv false and set stripe live mode secret key so it's not working and getting issue as upload image above.
Error Image:-

Related

How to send and verify OTP using cloud function in flutter?

I have API to send and verify otp code. I need to link that API to my flutter app using Firebase clod function. How is it possible Please help ?
Setup firebase cloud function here
Your js code be like
exports.sendOtp = functions.https.onCall((request, response) => {
const options = JSON.stringify({
mobile: request.text,
});
const headers = {
"Authorization": "Bearer xxxxxxxxxxxxxxxxxxxxxxx”,
};
const res = axios.post(“url”, options, {headers: headers}).then((response) => {
console.log(response);
return response;
});
return res.statusCode;
});
Your service code be like
Future<void> sendOtp(String mobile) async {
HttpsCallable callable =
FirebaseFunctions.instance.httpsCallable('sendOtp');
final resp = await callable.call(<String, dynamic>{
'text': mobile,
});
}

Flutter Stripe paymentsheet is opening webpage (hooks.stripe.com) while processing payments

I am developing a flutter application which uses stripe for payments. I am using https://pub.dev/packages/flutter_stripe for this.
Everything is working fine but whenever I initiate payments I always get a webpage middleware (Screenshots attached). What am I doing wrong?
Here is my implementation in Flutter
Future<void> makePayment(String planName, String type) async {
Fluttertoast.showToast(msg: "initiating Payments, Please wait.");
ApiProvider provider = ApiProvider();
final tokenResponse = await provider
.getPaymentToken(PlanPayment(planName: planName, type: type));
if (tokenResponse != null) {`
var _service = locator<NavigationService>();
String secret = tokenResponse.clientSecret;
// make a get call from this url
Map<String, dynamic> paymentIntentData = Map();
await payment.Stripe.instance.initPaymentSheet(
paymentSheetParameters: payment.SetupPaymentSheetParameters(
merchantCountryCode: 'IN',
testEnv: true,
paymentIntentClientSecret: secret,
googlePay: true,
));
try {
// await Stripe.instance.handleCardAction(secret);
await payment.Stripe.instance.presentPaymentSheet().then((value) {});
await payment.Stripe.instance
.confirmPaymentSheetPayment()
.then((value) async {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': true});
});
} catch (e) {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': false});
print("Stripe error" + e.toString());
}
await provider
.confirmPayment(tokenResponse.transactionId)
.then((value) async {
await _service
.pushReplacementNamed(paymentStatus, args: {"isSuccess": value});
});
}
}
`
Maybe you have a webhook put in your account?
1)Provide valid Secret key
2)Provide valid Publisable key
3)Update flutterstripe pacakge
4)provide valid currency code to create stripe account country
ex :- stripe account create india to inr etc..
5)Right Way to implemet
- Main.dart to main method run app to implemet
ex :--
Stripe.publishableKey = "your publishable key ";
- create controller / method
code:-
Map<String, dynamic>? paymentIntentData;
Future<void> makePayment({amount}) async {
try {
paymentIntentData =
await createPaymentIntent(amount: amount, currency: 'INR');
if (paymentIntentData != null) {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
// applePay: true,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'INR'),
merchantDisplayName: "PGA",
customerId: paymentIntentData!['customer'],
paymentIntentClientSecret: paymentIntentData!['client_secret'],
customerEphemeralKeySecret: paymentIntentData!['ephemeralkey'],
));
}
displayPaymentSheet();
} catch (err) {
logger.e(err);
}
}
void displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet();
Get.snackbar("PaymentInfo", "Payment Successfully");
} on Exception catch (e) {
if (e is StripeException) {
logger.e(e, "Error From Stripe");
} else {
logger.e(e, "Unforeseen error");
}
} catch (e) {
logger.e("exeption === $e");
}
}
var id = "";
createPaymentIntent({amount, currency}) async {
try {
Map<String, dynamic> body = {
'amount': calculateAmount(amount: amount),
'currency': currency,
'payment_method_types[]': 'card'
};
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
headers: {
'Authorization':
'Bearer YourSecretKey',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body,
);
if (response.statusCode == 200) {
var decode = jsonDecode(response.body);
logger.e(decode);
id = decode['id'];
return decode;
}
} catch (e) {
logger.e(e, "error charging user");
}
}
calculateAmount({amount}) {
logger.e(amount.round());
final a = (int.parse(amount.toString())) * 100;
logger.e(a.toString());
update();
return a.toString();
}
6) How to Access Stripe payment :-
ex :- any button click
ontap : (){
makePayment(
amount: "200")
}

How to pass data to cloud function file in flutter

I am new to flutter and I have just created app that accepts payments from user using flutter_stripe: ^2.1.0 plugin. The amount in cloud function file index.js is fixed but I want to pass the amount that is calculated dynamically. Here is my code.
Future<void> makePayment() async {
final url = Uri.parse(
'https://us-central1-carwashapp-376b6.cloudfunctions.net/stripePayment');
final response =
await http.get(url, headers: {"Content-Type": "application/json"});
paymentIntentData = json.decode(response.body);
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['paymentIntent'],
applePay: true,
googlePay: true,
style: ThemeMode.light,
merchantCountryCode: 'US',
merchantDisplayName: 'Kleen My Car',
),
);
setState(() {});
displayPaymentSheet();
}
Future<void> displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet(
parameters: PresentPaymentSheetParameters(
clientSecret: paymentIntentData['paymentIntent'],
confirmPayment: true));
setState(() {
paymentIntentData = null;
});
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Payment succeeded')));
} catch (e) {
print('error error error');
}
}
and here is my index.js file's code
const functions = require("firebase-functions");
const stripe = require("stripe")(functions.config().stripe.testkey);
exports.stripePayment = functions.https.onRequest(async (req, res) => {
const paymentIntent = await stripe.paymentIntents.create(
{
amount: 120,
currency: "USD",
},
function (err, paymentIntent) {
if (err != null) {
console.log(err);
} else {
res.json({
paymentIntent: paymentIntent.client_secret,
});
}
}
);
});
Any kind of help is much appreciated. Thank you so much!
You need to adapt this line:
final response = await http.get(url, headers: {"Content-Type": "application/json"});
(Firstly, it makes no sense to give a content type on a GET, as GETs don't have any content. Remove that header.)
You could change to a POST and add the amount as a parameter, or leave it as a GET and add the amount to the URL.
With a POST, add (for example) body: {'amount': amount.toString()}
With a GET, add it to the URL, as follows:
final uri = Uri.https('us-central1-carwashapp-376b6.cloudfunctions.net', '/stripepayment', {'amount': amount.toString()});
In your cloud function access amount from the req. (For example, in the GET example, it would be req.query.amount as string.)
We also pass up other parameters like email, unique order id (to be used as the idempotency key), etc.
in index.js file change
const paymentIntent = await stripe.paymentIntents.create(
{
amount: 120,
currency: "USD",
},
to
const paymentIntent = await stripe.paymentIntents.create(
{
amount: req.query.amount,
currency: req.query.currency,
},
and deploy your function.
after that, in makepayment function, change your URL to
https://us-central1-carwashapp-376b6.cloudfunctions.net/stripePayment?amount=$amount&currency=$currency.
In this way, you can pass different amounts every time by changing the value of $amount variable in the URL.

How do I hook up a cross platform Flutter app with Azure AD

I have a cross platform application (mobile, desktop and web) created in Flutter that I would like to set up to be authenticated with Azure AD.
I know that there are some packages that you can add for mobile and maybe even for web but I am unable to find a working solution for desktop.
I thought that I could open the browser on the device and use that to sign the user in, but it would need a URI to redirect to when the user is authenticated and for the application to be able to get the token that I can then use to make calls to my API. I can't see how that would work though, due to the application being hosted on the users device and not on a server with a set IP like with websites.
Any possible solutions or guidance would be greatly appreciated.
I ended up using a combination of this older tutorial for Facebook authentication along with Microsoft documentation on how to get a token for native apps to create a small authenticating service seen below.
I used the following pub packages:
url_launcher
flutter_dotenv
http
Auth Service:
import 'dart:async';
import 'dart:io';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:research_library_viewer/Models/Token.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:http/http.dart' as http;
class AuthenticationService {
String tenant = dotenv.env['MSAL_TENANT']!;
String clientId = dotenv.env['MSAL_CLIENT_ID']!;
String clientSecret = dotenv.env['MSAL_CLIENT_SECRET']!;
String redirectURI = dotenv.env['MSAL_LOGIN_REDIRECT_URI']!;
String scope = dotenv.env['MSAL_CLIENT_SCOPE']!;
String authority = dotenv.env['MSAL_AUTHORITY_URI']!;
Future<Stream<String>> _server() async {
final StreamController<String> onCode = StreamController();
HttpServer server =
await HttpServer.bind(InternetAddress.loopbackIPv4, 8080);
server.listen((HttpRequest request) async {
final String? code = request.uri.queryParameters["code"];
request.response
..statusCode = 200
..headers.set("Content-Type", ContentType.html.mimeType)
..write("<html><h1>You can now close this window</h1></html>");
await request.response.close();
await server.close(force: true);
if (code != null) {
onCode.add(code);
await onCode.close();
}
});
return onCode.stream;
}
String getAuthUrl() {
String authUrl =
"http://$authority/$tenant/oauth2/v2.0/authorize?client_id=$clientId&response_type=code&redirect_uri=$redirectURI&response_mode=query&scope=$scope";
return authUrl;
}
Map<String, dynamic> getTokenParameters(String token, bool refresh) {
Map<String, dynamic> tokenParameters = <String, dynamic>{};
tokenParameters["client_id"] = clientId;
tokenParameters["scope"] = scope;
tokenParameters["client_secret"] = clientSecret;
if (refresh) {
tokenParameters["refresh_token"] = token;
tokenParameters["grant_type"] = "refresh_token";
} else {
tokenParameters["code"] = token;
tokenParameters["redirect_uri"] = redirectURI;
tokenParameters["grant_type"] = "authorization_code";
}
return tokenParameters;
}
Future<Token> getToken() async {
String url = getAuthUrl();
Stream<String> onCode = await _server();
if (await canLaunch(url)) {
await launch(url);
} else {
throw "Could not launch $url";
}
final String code = await onCode.first;
final Map<String, dynamic> tokenParameters =
getTokenParameters(code, false);
final response = await http.post(
Uri.https(
'login.microsoftonline.com',
'$tenant/oauth2/v2.0/token',
),
headers: <String, String>{
'Content-Type': 'application/x-www-form-urlencoded'
},
body: tokenParameters);
if (response.statusCode == 200) {
return tokenFromJson(response.body);
} else {
throw Exception('Failed to acquire token');
}
}
Future<Token> refreshToken(String? refreshToken) async {
if (refreshToken == null) {
return getToken();
} else {
final Map<String, dynamic> tokenParameters = getTokenParameters(refreshToken, true);
final response = await http.post(
Uri.https(
'login.microsoftonline.com',
'$tenant/oauth2/v2.0/token',
),
headers: <String, String>{
'Content-Type': 'application/x-www-form-urlencoded'
},
body: tokenParameters);
if (response.statusCode == 200) {
return tokenFromJson(response.body);
} else {
throw Exception('Failed to acquire token');
}
}
}
}
Token:
import 'dart:convert';
Token tokenFromJson(String str) {
final jsonData = json.decode(str);
return Token.fromJson(jsonData);
}
class Token {
String accessToken;
String tokenType;
num? expiresIn;
String? refreshToken;
String? idToken;
String? scope;
Token({
required this.accessToken,
required this.tokenType,
this.expiresIn,
this.refreshToken,
this.idToken,
this.scope,
});
factory Token.fromJson(Map<String, dynamic> json) => Token(
accessToken: json["access_token"],
tokenType: json["token_type"],
expiresIn: json["expires_in"],
refreshToken: json["refresh_token"],
idToken: json["id_token"],
scope: json["scope"],
);
Map<String, dynamic> toJson() => {
"access_token": accessToken,
"token_type": tokenType,
"expires_in": expiresIn,
"refresh_token": refreshToken,
"id_token": idToken,
"scope": scope,
};
}
I think that this could still be improved a lot, but it is definitely something to start with if you are sitting with a similar challenge.
Found an MS document you can follow to add Azure Authentication in your Desktop application.
Refer this : Sign-in a user with the Microsoft Identity Platform in a WPF Desktop application and call an ASP.NET Core Web API
There is also another way for the same but with Azure AD B2C : Configure authentication in a sample WPF desktop app by using Azure AD B2C
The application registration and architecture are illustrated in the following diagrams:

Pinterest Oauth2 Access Token Issue

I have a Flutter app that I'm trying to integrate with Pinterest, and I'm a little stuck.
I have code to request an access token and, while the code does get an access token, that token does not appear to be useful. Any API that I call with that token results in a 308, and if I go to the Pinterest developer site and debug the token, then it looks like this:
So, it's like the token has no scopes and was not issued for an actual application, which is very weird. The code I have looks like this:
Future<String> _login() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
accessToken = null;
if (accessToken == null) {
// accessToken = prefs.get(ACCESS_TOKEN_KEY);
//If we don't have an existing access token, get a new one.
if (accessToken == null) {
final appId = "myappid";
final secret =
"mysecret";
final url = Uri.https('api.pinterest.com', 'oauth', {
'response_type': 'code',
'client_id': appId,
'redirect_uri': "pdk<myappid>://",
'state': 'someBogusStuff',
'scope': 'read_public,write_public',
});
final result = await FlutterWebAuth.authenticate(
url: url.toString(), callbackUrlScheme: 'pdk<myappid>');
print(result);
final tokenEndpoint = Uri.https('api.pinterest.com', 'v1/oauth/token');
// Use the code to get an access token
final response = await http.post(tokenEndpoint, body: {
'client_id': appId,
'client_secret': secret,
'grant_type': 'authorization_code',
'code': Uri
.parse(result)
.queryParameters['code'],
});
if (response.statusCode != 200) {
return response.body;
}
var decodedResponse = jsonDecode(response.body);
print(decodedResponse);
accessToken = decodedResponse['access_token'];
//Save the access token
prefs.setString(ACCESS_TOKEN_KEY, accessToken);
}
}
return getMe(accessToken);
}
Future<String> getMe(String token) async {
final url =
Uri.https('api.pinterest.com', 'v1/me', {'access_token': token});
Completer<String> completer = Completer();
String result;
http.get(url, headers: {'User-Agent': 'PDK 1.0'}).then((response) {
print(response.statusCode);
result = response.body;
}).whenComplete(() => completer.complete(result));
return completer.future;
}
When I print out the result of the call to /oauth/token it looks like I got back a good token:
{access_token: AvtF3MxUy4gbujGGhN_KcYFExQVAFfmOZGmxYN5GkhE-iKDH6QpYADAAAzbHRpc4dD1gvFwAAAAA, token_type: bearer, scope: [read_write_all, read_public, write_public, read_private, write_private]}
But it doesn't work. What am I doing wrong here?