In my app's main.dart, I ran the following code:
final fcmToken = await FirebaseMessaging.instance.getToken();
I took the token and used it in my cloud function:
exports.notifyUserAddedToGroup = functions.firestore
.document("groups/{groupDocID}/groupMembers/{groupMembersDocID}")
.onWrite((change, context) => {
const FCMToken = `loooooooooooooooooooooooooooooooong
fcmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
tokennnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn`;
const payload = {
token: FCMToken,
notification: {
title: "Title",
body: "Body",
},
data: {
body: "data body",
},
};
admin.messaging().send(payload)
.then((response) => {
console.info("##MyApp## function executed successfully");
return {msg: "##MyApp## function executed succesfully"};
})
.catch((error) => {
console.info("##MyApp## error in execution");
console.log(error);
return {msg: "##MyApp## error in execution"};
});
});
I then went to Firestore and added a document into the correct collection to trigger the cloud function. When I went to the google cloud console logs, I saw the following error:
The registration token is not a valid FCM registration token
Why is my token invalid if I just generated it a few minutes before triggering the cloud function?
The problem was the hard coded FCM token in the function. I put the token in Firestore instead and queried it to use it in the function and it worked.
Related
I am new to nextauth credentials provider, and I have been following different tutorials on youtube and searching for answers here.
I have a web application using next.js and in it I have a bunch of rest apis to get data from mongodb. I have secured the api by accessing the token. I have used Postman to test the apis, and they work when I pass the raw token to in the Authorization header.
I need to get the raw token into the session object for the session call back in next-auth, so I then can call the apis from client side pages.
Any help would be appreciated.
In [...nextauth].js:
export default NextAuth({
providers: [
// Google Provider
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET
}),
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET
}),
CredentialsProvider({
id: "credentials",
name: "Credentials",
async authorize(credentials, req) {
console.log("In Authorization");
connectMongo().catch((error) => {
error: "Connection Failed...!";
});
// check user existance
const user = await Users.findOne({ email: credentials.email });
if (!user) {
throw new Error("No user found with this email");
}
// compare()
const checkPassword = await compare(
credentials.password,
user.password
);
// incorrect password
if (!checkPassword || user.email !== credentials.email) {
throw new Error("Email or Password don't match");
}
// check if user is enabled
if (user.active === AccountStatus.DISABLED) {
throw new Error(
"Account has been disabled. Please contact support to re-enable your account"
);
}
// Value returned will go into token property
//console.log("Returnng User Object", user);
return user;
}
})
],
session: {
strategy: "jwt",
maxAge: 60 * 60 * 24
},
callbacks: {
async jwt({ token, user, account, profile, isNewUser }) {
if (user) token.user = user;
if (account) token.accessToken = account.access_token;
return token;
},
async session({ session, token, user, account }) {
// Send properties to the client, like an access_token from a provider.
const { password, ...tokenPwdRemoved } = token.user;
session.user = tokenPwdRemoved;
return session;
}
},
pages: {
signIn: "/login"
}
});
Take a look at the Session callback:
callbacks: {
async session({ session, token, user }) {
// Send properties to the client, like an access_token from a provider.
session.accessToken = token.accessToken
return session
}
}
Keep in mind security concerns relating to the token and session.
Session callback
The session callback is called whenever a session is checked. By
default, only a subset of the token is returned for increased
security. If you want to make something available you added to the
token through the jwt() callback, you have to explicitly forward it
here to make it available to the client.
I need to fetch the user token from the firestore in a cloud function.
the user token was stored as follows:
void saveToken(String token) async {
await FirebaseFirestore.instance
.collection("User tokens")
.doc(userId)
.set({'token': token});
}
here is the goal.
When a message is created on the collection 'chat messages',
grab the "Chat id" value and the user who sends the message "User id".
query the collection "chat" using the "Chat id" value,
grab the "Job users data" value (this is an array with two objects, each object contains the users involved in the chat (userName,userId) ).
from the "Job users data", I need to grab the userId of the member who should be receiving the message.
query "User tokens" collection to grab the "token" value.
use the "token" value, to send a notification to
here is my cloud function:
as you see, I have hardcoded the token to see if I could send that device a notification.... that works perfect. now I need to to make this dynamic...
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { database } = require("firebase-admin");
// eslint-disable-next-line max-len
const tokens = ["JNKDNASNDAUIU324234....."];
admin.initializeApp();
// exports.onCreate = functions.firestore
// .document("chat/{docId}")
// .onCreate((snapshot, context) => {
// console.log(snapshot.data());
// console.log("fake data");
// });
exports.onChatMessageCreate = functions.firestore
.document("chat messages/{docId}")
.onCreate( (snapshot, context) => {
console.log(snapshot.data());
// fetch user to send message to
// admin.database().ref("/")
const payload = {
// eslint-disable-next-line max-len
notification: {title: snapshot.data()["userName"], body: snapshot.data()["Chat message"], sound: "default"},
// eslint-disable-next-line max-len
data: {click_action: "FLUTTER_NOTIFICATION_CLICK", message: "Sample Push Message"},
};
try {
admin.messaging().sendToDevice(tokens, payload);
console.log("NOTIFICATION SEND SUCCESSFULLY");
} catch (e) {
console.log("ERROR SENDING NOTIFICATION");
console.log(e);
}
});
So all i need to know is how to query collections from a cloud function
There are 2 ways to query a collection in Node.js. either through then() or async/await.
to query using promise:
const collectionRef = admin.firestore().collection("yourCollection");
return collectionRef.get().then((collections) => {
//you can now use your collections here
});
using async/await:
const collectionRef = admin.firestore().collection("yourCollection");
const collections = await collectionRef.get();
I have a website where when user logsIn, they are assigned an access and a refresh token. When the access token is expried, a request to the server is made and checks if the refresh token is present in the global array in the database. If it is, a new access token is assigned to the user.
But I wanted to ask if should also check for the user by the information given by the refresh token when it is decoded. Or it is not necessary.
Please suggest me good practice and also tell me if something is wrong with my process.
routes.post("/newAccessToken", async (req, res) => {
const token = req.headers.cookie?.split("=")[1];
try {
const existingToken = await refreshTokens.findOne({
tokens: { $in: [token] },
});
if (existingToken) {
const email = await jwt.verify(token, process.env.RefreshTokenSecret);
if (email) {
const user = await userSchema.findOne({ email });
if (user) {
const newAccessToken = await jwt.sign(
{ email },
process.env.AccessTokenSecret
);
res.json({ newAccessToken });
}
} else res.json({ message: "token is invalid" });
} else res.json({ message: "No token found" });
} catch (error) {
console.log(error);
}
});
I'm using Firebase functions for creating seller account but I don't know how to create seller account and what to put in the redirect_url
I followed some tutorials and wrote the below code
Let me know what changes should I do to open seller account registration with url_launcher
Thanks
const stripeAccount = functions.https.onRequest(async (req, res) => {
const { method } = req
if (method === "GET") {
// CREATE CONNECTED ACCOUNT
const { mobile } = req.query
const account = await stripe.accounts.create({
type: "express",
})
const accountLinks = await stripe.accountLinks.create({
account: account.id,
refresh_url:, <-- What to put here
return_url:, <-- What to put here
type: "account_onboarding",
})
if (mobile) {
// In case of request generated from the flutter app, return a json response
res.status(200).json({ success: true, url: accountLinks.url })
} else {
// In case of request generated from the web app, redirect
res.redirect(accountLinks.url)
}
} else if (method === "DELETE") {
// Delete the Connected Account having provided ID
const {
query: { id },
} = req
console.log(id)
const deleted = await stripe.accounts.del(id)
res.status(200).json({ message: "account deleted successfully", deleted })
} else if (method === "POST") {
// Retrieve the Connected Account for the provided ID
// I know it shouldn't be a POST call. Don't judge :D I had a lot on my plate
const account = await stripe.accounts.retrieve(req.query.id)
res.status(200).json({ account })
}
const stripeReAuth = async (req, res) => {
const { account_id: accountId } = req.query
const accountLinks = await stripe.accountLinks.create({
account: accountId,
refresh_url: <-- Here
return_url: , <-- Here
type: "account_onboarding",
})
res.redirect(accountLinks.url)
}
})
This is my flutter code, I'm retrieving the return_url and launching it with url_launcher
class StripeBackendService {
static String apiBase = '{function address}/stripeAccount';
static String createAccountUrl =
'$apiBase/account?mobile=true';
static String checkoutSessionUrl =
'${StripeBackendService.apiBase}/checkout-session?mobile=true';
static Map<String, String> headers = {'Content-Type': 'application/json'};
void createSellerAccount() async {
var url = Uri.parse(StripeBackendService.createAccountUrl);
var response = await http.get(url, headers: StripeBackendService.headers);
Map<String, dynamic> body = jsonDecode(response.body.toString());
await canLaunch(body['url']) ? await launch(body['url']) : throw 'Error'
}
}
The refresh url should point to an address that retries the creation of the stripe connect account, in case your current http function returns an expired link. The return url is the address that the potential stripe connect user gets sent to after the stripe onboarding is complete. In knowing that address you can use the webview controller to jump back to the app when reaching that return-url endpoint.
I saw some other answers and I tried some of those unsuccessfully.
In my case, I created an iOS app and integrated Stripe payment method, so it reaches my javascript function at cloud functions. I'm actually able to see the payments I realizes within my stripe account but I couldn't manage to save it into our firestore database.
this is my setup at Google side:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const express = require('express');
const cors = require('cors')({origin: true});
const app = express();
const stripe = require('stripe')(functions.config().stripe.token);
//I've preset this data to firebase functions middleware
function charge(req, res) {
const body = (req.body);
const userId = body.userId;
const token = body.token;
const amount = body.amount;
const currency = body.currency;
// Charge card
stripe.charges.create({
amount,
currency,
description: 'Firebase Example',
source: token,
}).then(charge => {
send(res, 200, {
// I WANNA RECORD DATA INTO MY DATABASE HERE!!
message: 'Success',
charge,
});
}).catch(err => {
console.log(err);
send(res, 500, {
error: err.message,
});
});
}
function send(res, code, body) {
res.send({
statusCode: code,
body: JSON.stringify(body),
});
}
app.use(cors);
app.post('/', (req, res) => {
// Catch any unexpected errors to prevent crashing
try {
charge(req, res);
} catch(e) {
console.log(e);
send(res, 500, {
error: `The server received an unexpected error. Please
try again and contact the site admin if the error persists.`,
});
}
});
exports.charge = functions.https.onRequest(app);
And this is our database setup where I want to save like this:
- into payments > userId... I'll save each transaction this userId does with the fields: "token", "currency" and "amount".
Note: I already have all this values in my function and also have userId.
enter image description here