I am learning cloud functions.
I have this function:
exports.sendFCM = functions.https.onRequest(async (request, response) => {
const data = request.body.data;
...
});
I need iside this function get the user UID:
const uid = context.auth.uid;
But I do not have context there.
I can get UID like this:
exports.getUid = functions.https.onCall((data, context) => {
const uid = context.auth.uid;
return `response: ${uid}`;
});
Basicallty, how I call getUid inside sendFCM ?
There is no context in HTTP functions at all like there is in background functions, so what you're trying to do isn't possible as you're asking. There is only the input to the function in the Request object and the response you generate in the Response object.
If you want to know who is making the request, you need to code your app to pass along the authenticated user token in the request and validate it using the Firebase Admin SDK. You can read the documentation about that. Note that callable type functions do all this for you behind the scenes.
Related
This question already has answers here:
Where do the parameters in a javascript callback function come from?
(3 answers)
Closed 6 months ago.
I see code like below in almost every NodeJS application:
const express = require("express");
const app = express();
app.post("/some-route", (req, res) => {
const data = req.body;
}
What I can not understand is where does the res come from? I can understand req comes from with the request that user/client application sends to the backend app, but what is this res object we should pass to the callback function almost always we want to write such a route handler function?
Isn't res what we should make in our handler function and send it back to the user? If so, how can we receive it as an input in our callback function?
Is this correct to say "Whenever the Express server receives a new request, it automatically creates a response object, and gives us the option to manipulate/modify this res object through the callback function? So we can either use this option and do something on that, then send it back to the client, or do nothing and express will send it's default or automatically created response back to the user"?
If so, what does a default express res object look like?
Express just calls your function with the arguments
Check the example below:
const app = {
post: (callback) => {
callback('value1', 'value2')
}
}
app.post((req, res) => {
console.log(req, res)
})
app.post((first, second) => {
console.log(first, second)
})
Here I create a custom post function which takes a function as a parameter. Then my post function calls the provided function with two arguments.
Take notice that these parameters can have arbitrary names, not only req and res
I have a GraphQL API (TypeScript, Express, apollo-server), which is being consumed by a client app. All requests require authentication by validating the JWT token like this:
return new ApolloServer({
schema,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
context: async ({ req }) => {
const user = await validateJWT(ctx, req)
return { ...ctx, user }
},
})
(Ignore ctx, it's an implementation specific detail.)
My problem here is that I need to allow a specific query to be unauthenticated. During the onboarding, the client is fetching data before the user is even created.
type Query {
onboardingData(profile: ProfileInput!): OnboardingData!
...
}
What is the appropriate way of bypassing authentication for a particular query?
I've looked into using
import { parse, print } from 'graphql'
to get the query from req.body.query and then do string-matching, but that feels janky, to say the least. My Spidey-senses are tingling that it's prone to errors, confusion and potential vulnerabilities.
In a REST world, I would just specify a particular path to be excluded.
You can get you context to return the function that gets your user, instead of getting the user in the context level and returning it to the resolvers. Wrap your context body in a function and return the function. Then on your resolvers that require authentication and / or the current user, you simply call it, similar to the way you call it in the context body.
Example:
const user = await validateJWT()
Or better named:
const user = await getCurrentUser()
This approach gives you flexibility to only call it on resolvers that require authentication.
I am trying to get some records from Mongo db based on a query. I completed the Back-end and it works well with the Postman but I do not know how to send the variable for the query from react front end to the back end.
There is a Client model class and I want to retrieve all the clients with a specific company ID which I will be sending from Front end on a button click.
Controller.js
exports.viewSpecificClients = async(req,res)=>{
const id = req.query.id;
console.log(id);
try{
const clients = await Client.find({clientCompanyName: id});
res.json({clients});
}catch(err){
console.log(err, 'clientsController.viewSpecificClients error');
res.status(500).json({
errorMessage: 'Please try again later'
})
}
};
Route
router.get('/', clientsController.viewSpecificClients);
I have to use Redux, so I tried do do this but I could only manage to display all the clients in the database (I do not know how to send the variable).
Action.js in Redux
export const getClients = () => async dispatch =>{
try{
const response = await axios.get('clients');
dispatch({
type: GET_CLIENTS,
payload: response.data.clients
});
}catch(err){
console.log('getClients api error:', err);
}
}
Can you please help me on how I can send the company id from front-end using redux - that is I want help with how to change the action function and also what do I have to do in the main.js file when the button is clicked ?
if you have access to companyId at the front end, all you need to do is
const response = await axios.get(`clients?id=${companyId}`);
assuming backend express is configured with query parser already.(by default)
may be you can have
const getClients = (companyId) => dispatch => {
const response = await axios.get(`clients?id=${companyId}`);
// above code here
}
let me know if you need further follow up.
You have two options there. First you pass the value of parameter as query string. The other option is to modificate your get request to a POST request where you can add request body. The post request is better if you try to pass more value like an object.
I have created this cloud function:
exports.returnUid = functions.https.onRequest(async(req, res) => {
const uid = req.query.uid
res.send(uid)
});
When I call https://<project>.cloudfunctions.net/returnUid?uid=123abc, it returns an empty response, and not the "uid" parameter as it should.
I've found out that when using firebase --serve, the function won't acept parameters. But when I deplpoy it, it does.
Is there a way to check if a user is firebase-authorized before triggering a cloud function? (Or within the function)
Yes. You will need to send the Firebase ID token along with the request (for example in the Authorization header of an AJAX request), then verify it using the Firebase Admin SDK. There is an in-depth example in the Cloud Functions for Firebase samples repository. It looks something like this (made shorter for SO post):
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')();
const validateFirebaseIdToken = (req, res, next) => {
cors(req, res, () => {
const idToken = req.headers.authorization.split('Bearer ')[1];
admin.auth().verifyIdToken(idToken).then(decodedIdToken => {
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
next();
}).catch(error => {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
});
});
};
exports.myFn = functions.https.onRequest((req, res) => {
validateFirebaseIdToken(req, res, () => {
// now you know they're authorized and `req.user` has info about them
});
});
Since the question asks for auth-based access (1) within, or (2) before a function, here's an method for the "before" case: >
Since every Firebase Project is also a Google Cloud Project -- and GCP allows for "private" functions, you can set project-wide or per-function permissions outside the function(s), so that only authenticated users can cause the function to fire.
Unauthorized users will be rejected before function invocation, even if they try to hit the endpoint.
Here's documentation on setting permissions and authenticating users. As of writing, I believe using this method requires users to have a Google account to authenticate.