I try to implement Stripe on my Flutter Firebase project but I've got an issue.
Here's my code :
Future<void> makePayment () async {
final url = Uri.parse('***********');
final response = await http.get(url,
headers: {
'Content-Type': 'application/json'
});
paymentIntentData = json.decode(response.body);
// Here's the issue
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData!['paymentIntent'],
applePay: true,
googlePay: true,
style: ThemeMode.dark,
merchantCountryCode: 'US',
merchantDisplayName: 'Test',
)
);
setState(() {
});
displayPaymentSheet();
}
Got this error :
FormatException (FormatException: Unexpected character (at character 1)
Error: could not handle the request
^
)
I've tried to search the reason it returns this error, but can not find. Please someone can explain me what I'm doing wrong ? I don't want bother you with too much code, if you need anything to help me understand where is my mistake, just let me know.
Hi you can check the Logs in Stripe Dashboard https://dashboard.stripe.com/logs and see if the Payment Intent is created successfully.
Related
I am trying to add a user to my workspace in Clockify however I am getting Bad Request Error: status Code 400.
Can someone help. The API docs are not very helpful. Not sure what is wrong, is it my payload is wrong or am I missing anything in headers?
Thanks for helping. Code below:
const addUser = async (req, res) => {
const url = `https://api.clockify.me/api/v1/workspaces/${workspaceId}`;
try {
const payload = JSON.stringify(req.body);
console.log("DATA", payload); // prints {"email": "max#gmail.com"}
const records = await axios.post(`${url}/users/`, payload, {
headers: {
"X-Api-Key": key,
"content-type": "application/json",
},
});
console.log("Response", records);
res.status(200).json(records);
} catch (error) {
res.statusCode = error.response.status;
res.json({
msg: `Something went wrong. Error: ${error.response.status} with clockify data posting`,
});
console.log(
`Something went wrong :confused:!! Error with clockify data posting`,
error.message
);
}
};
Adding User Via API to clockify is only possible when your workspace is on a paid subscription
I've been working on this for a while now and feel like I've read everything I can find but still can't get it to work. I'm trying to build a Firebase callable cloud function that uses axios to get a Spotify access token through client credentials auth flow and then uses that token to get data from my own account from the Spotify API. I'm using a chained function starting with axios.post and then axios.get.
The code works when it's getting the access token through axios.post but as soon as I chain an axios.get to use the token with the API something goes wrong. I'm new to Firebase and node.js so am not sure exactly how to catch the errors properly. The most common error is either a null result or a 'Unhandled error RangeError: Maximum call stack size exceeded' in the Firebase log... can't work out what either actually means for my code... With this particular version of my code I get a null result and a mass of around 50 different error logs in Firebase.
I've tried splitting the functions, using async and await and different arrangements of the headers but not a lot really changes. I've found similar questions but nothing that seemed to solve the issue. Any help would be amazing!
const functions = require("firebase-functions");
const axios = require('axios');
const qs = require('qs');
exports.spot = functions.https.onCall( async (data, context) => {
const client_id = //REMOVED;
const client_secret = //REMOVED;
const auth_token = Buffer.from(`${client_id}:${client_secret}`, 'utf-8').toString('base64');
const token_url = 'https://accounts.spotify.com/api/token';
const stringify_data = qs.stringify({'grant_type':'client_credentials'});
const api_url = 'https://api.spotify.com/v1/recommendations'
return axios
.post(token_url, stringify_data, {
headers: {
'Authorization': `Basic ${auth_token}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
grant_type: 'client_credentials'
},
json: true
})
.then(result => {
return axios.get(api_url, {
headers: {
'Authorization': `Bearer ${result.data.access_token}`,
}
})
})
.then(result => {
return result
})
.catch(error => {
console.log(error);
})
});
I want to test a a cloud function that creates users.
In normal cases, inside the browser i generate an idToken and i send it to server via headers: Authorization : Bearer etcIdToken
But I want to test this function without the browser. In my mocha tests i have:
before(done => {
firebase = require firebase.. -- this is suppose to be like the browser lib.
admin = require admin..
idToken = null;
uid = "AY8HrgYIeuQswolbLl53pjdJw8b2";
admin.auth()
.createCustomToken(uid) -- admin creates a customToken
.then(customToken => {
return firebase.auth() -- this is like browser code. customToken get's passed to the browser.
.signInWithCustomToken(customToken) -- browser signs in.
.then(signedInUser => firebase.auth() -- now i want to get an idToken. But this gives me an error.
.currentUser.getIdToken())
})
.then(idToken_ => {
idToken = idToken_
done();
})
.catch(err => done(err));
})
The error i'm getting is:
firebase.auth(...).currentUser.getIdToken is not a function - getting the idToken like this works on client - and is documented here.
I tried directly with signedInUser.getIdToken(). Same problem:
signedInUser.getIdToken is not a function - not documented. just a test.
I think this is because firebase object is not intended for node.js use like i'm doing here. When signing in - stuff get's saved in browser local storage - and maybe this is why.
But the question still remains. How can i get an idToken inside node.js in order to be able to test:
return chai.request(myFunctions.manageUsers)
.post("/create")
.set("Authorization", "Bearer " + idToken) --- i need the idToken here - like would be if i'm getting it from the browser.
.send({
displayName: "jony",
email: "jony#gmail.com",
password: "123456"
})
am I approaching this wrong? I know that if i can get the idToken it will work. Do i rely need the browser for this? Thanks :)
From Exchange custom token for an ID and refresh token, you can transform a custom token to an id token with the api. Hence, you just have to generate a custom token first from the uid, then transform it in a custom token. Here is my sample:
const admin = require('firebase-admin');
const config = require('config');
const rp = require('request-promise');
module.exports.getIdToken = async uid => {
const customToken = await admin.auth().createCustomToken(uid)
const res = await rp({
url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${config.get('firebase.apiKey')}`,
method: 'POST',
body: {
token: customToken,
returnSecureToken: true
},
json: true,
});
return res.idToken;
};
L. Meyer's Answer Worked for me.
But, the rp npm package is deprecated and is no longer used.
Here is the modified working code using axios.
const axios = require('axios').default;
const admin = require('firebase-admin');
const FIREBASE_API_KEY = 'YOUR_API_KEY_FROM_FIREBASE_CONSOLE';
const createIdTokenfromCustomToken = async uid => {
try {
const customToken = await admin.auth().createCustomToken(uid);
const res = await axios({
url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${FIREBASE_API_KEY}`,
method: 'post',
data: {
token: customToken,
returnSecureToken: true
},
json: true,
});
return res.data.idToken;
} catch (e) {
console.log(e);
}
}
curl 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=<FIREBASE_KEY>' -H 'Content-Type: application/json'--data-binary '{"email": "test#test.com","password":"test","returnSecureToken":true}'
If this curl doesn't run, try running the same thing on Postman. It works!
In the past, I have used firebase.auth in the web client and once a user creates another user, I link certain security logic:
Once the user has been created I send an email to verify your email
with the function user.sendEmailVerification ().
As the user was created by another user, I assign a default password
and use the sendPasswordResetEmail () function so that the user
registers his new password.
That has worked well for me so far, but now for many reasons I need to move that logic to my server, for that I'm developing a backend with cloud functions and I'm using the Node.js Firebase Admin SDK version 6.4.0, but I can not find a way to use the functions of user.sendEmailVerification() and sendPasswordResetEmail() to implement the same logic on the server, the closest thing I found was:
auth.generateEmailVerificationLink (email)
auth.generatePasswordResetLink (email)
But it only generates a link for each one, which by the way the only emailVerification() serves me, the one from generatePasswordReset always tells me:
Try resetting your password again
Your request to reset your password has expired or the link has
already been used.
Even though be a new link, and it has not been used.
My 3 questions would be:
How can I make the sendEmailVerification () and
sendPasswordResetEmail () functions work on the server?
How can I make the link generated with
auth.generatePasswordResetLink (email) work correctly on the server?
Is there any way to use templates and emails on the server that are
in firebase auth?
Thank you in advance for sharing your experience with me, with all the programmers' community of stack overflow.
Those functions are not available in firebase-admin, but you should be able to run the client-side SDK (firebase) on the server as well. Not exactly a best practice, but it will get the job done. There's a long standing open feature request to support this functionality in the Admin SDK. You will find some helpful tips and workarounds there.
Could be a bug. I would consider reporting it along with a complete and minimal repro. The Admin SDK does have an integration test case for this use case, but it works slightly differently.
Not at the moment. Hopefully, this will be covered when the above feature request is eventually fulfilled.
The is a workaround provided here
https://github.com/firebase/firebase-admin-node/issues/46
I found a work-around that works well enough for my use case, see below. I'm not sure if this is best practice, but I wanted to keep the emails exactly the same between the server and client requests. Would love to hear about any flaws with this implementation 💡
As suggested above, it uses a three step process to do this:
Acquire a custom token via the admin sdk's createCustomToken(uid)
It converts this custom token to an idToken via the API
It invokes the send email verification endpoint on the API
const functions = require('firebase-functions');
const fetch = require('node-fetch');
const admin = require('firebase-admin');
const apikey = functions.config().project.apikey;
const exchangeCustomTokenEndpoint = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=${apikey}`;
const sendEmailVerificationEndpoint = `https://identitytoolkit.googleapis.com/v1/accounts:sendOobCode?key=${apikey}`;
module.exports = functions.auth.user().onCreate(async (user) => {
if (!user.emailVerified) {
try {
const customToken = await admin.auth().createCustomToken(user.uid);
const { idToken } = await fetch(exchangeCustomTokenEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: customToken,
returnSecureToken: true,
}),
}).then((res) => res.json());
const response = await fetch(sendEmailVerificationEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
requestType: 'VERIFY_EMAIL',
idToken: idToken,
}),
}).then((res) => res.json());
// eslint-disable-next-line no-console
console.log(`Sent email verification to ${response.email}`);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
});
I'm sure it doesn't matter anymore, but I had a headache doing this so I'd like to share even if it isn't the greatest answer.
await admin.auth().createUser(
{email, password, displayName, phoneNumber, photoURL}
).then(function(userRecord) {
admin.auth().createCustomToken(userRecord.uid).then(function(customToken){
createdToken=customToken;
firebase.auth().signInWithCustomToken(createdToken).catch(function(error){
return console.log(error)
})
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification().then(function(){
return console.log('It worked')
},function(error) {
return console.log(error)
})
});
})
})
I've been trying to get authy-client to run with Firebase Cloud Functions but I keep running into a ValidationFailedError. I've been testing the examples the author supplied at https://www.npmjs.com/package/authy-client with no luck.
For my Firebase function, I've been trying this:
const Client = require('authy-client').Client;
const client = new Client({ key: 'my API key here' });
exports.sendVerificationCode = functions.database.ref('users/{userId}/verify/status')
.onCreate(event => {
const sender = client.registerUser({
countryCode: 'US',
email: 'test#tester.com',
phone: '4035555555'
}).then( response => {
return response.user.id;
}).then( authyId => {
return client.requestSms({ authyId: authyId });
}).then( response => {
console.log(`SMS requested to ${response.cellphone}`);
throw Promise;
});
return Promise.all([sender]);
});
But I get this error:
ValidationFailedError: Validation Failed
at validate (/user_code/node_modules/authy-client/dist/src/validator.js:74:11)
at _bluebird2.default.try (/user_code/node_modules/authy-client/dist/src/client.js:632:31)
at tryCatcher (/user_code/node_modules/authy-client/node_modules/bluebird/js/release/util.js:16:23)
at Function.Promise.attempt.Promise.try (/user_code/node_modules/authy-client/node_modules/bluebird/js/release/method.js:39:29)
at Client.registerUser (/user_code/node_modules/authy-client/dist/src/client.js:617:34)
at exports.sendVerificationCode.functions.database.ref.onCreate.event (/user_code/index.js:24:25)
at Object.<anonymous> (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:59:27)
at next (native)
at /user_code/node_modules/firebase-functions/lib/cloud-functions.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:24:12)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:53:36)
at /var/tmp/worker/worker.js:695:26
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
I am new to Firebase' cloud functions so I may be overlooking something obvious but from what I've read, then() statements and the function itself needs to return/throw a Promise so I hacked that together.
I've also made sure that authy-client is included in the dependencies in the package.json file.
I originally signed up for the Twilio trial which gave me an option to create an application with Authy. Needing to be sure, I also signed in to Authy to check if the API key is the same, and they are. So I don't think the validation error is due to the API key.
Any help would be appreciated. Thank you.
Thank you all for your answers. I was finally able to figure out a solution. It had nothing to do with the code, well throw Promise was a mistake but it was apparently a problem with DNS resolutions that was resolved when I set up billing on Firebase.
As for my final code, as I originally wanted to use authy-client for phone verification, it looks something like this:
exports.sendVerificationCode = functions.database.ref('users/{userId}/verify')
.onCreate(event => {
const status = event.data.child('status').val();
const phoneNum = event.data.child('phone').val();
const countryCode = event.data.child('countryCode').val();
var method;
if(status === 'pendingSMS')
method = 'sms';
else
method = 'call';
// send code to phone
const sender = authy.startPhoneVerification({ countryCode: countryCode, phone: phoneNum, via: method })
.then( response => {
return response;
}).catch( error => {
throw error;
});
return Promise.all([sender]);
});
throw Promise doesn't really mean anything. If you want to capture problems that can occur anywhere in your sequence of promises, you should have a catch section. The general form is this:
return someAsyncFunction()
.then(...)
.then(...)
.catch(error => { console.error(error) })
That doesn't necessarily fix your error, though. That could be coming from the API you called.
Twilio developer evangelist here.
Doug is right about throw Promise, that will definitely need to be changed.
However, the error seems to be coming before that and from the API. Specifically, the stack trace tells us:
at Client.registerUser (/user_code/node_modules/authy-client/dist/src/client.js:617:34)
So the issue is within the registerUser function. The best thing to do is try to expose more of the error that is being generated from the API. That should give you the information you need.
Something like this should help:
const Client = require('authy-client').Client;
const client = new Client({ key: 'my API key here' });
exports.sendVerificationCode = functions.database.ref('users/{userId}/verify/status')
.onCreate(event => {
const sender = client.registerUser({
countryCode: 'US',
email: 'test#tester.com',
phone: '4035555555'
}).then( response => {
return response.user.id;
}).then( authyId => {
return client.requestSms({ authyId: authyId });
}).then( response => {
console.log(`SMS requested to ${response.cellphone}`);
}).catch( error => {
console.error(error.code);
console.error(error.message);
throw error;
});
});
Let me know if that helps at all.