Firebase Auth: updateProfile in Cloud Function? - javascript

I tried to use updateProfile() in my Cloud Function, triggered by HTTPS.
Error:
user.updateProfile is not a function
Cloud Function:
app.get("/user/create", (req, res) => {
res.setHeader('Content-Type', 'application/json')
admin.auth().verifyIdToken(req.query.token).then(user => {
let name = req.query.name
user.updateProfile({
displayName: name
}).then(() => {
res.send(JSON.stringify({
result: false,
error: err.message
}))
})
})
})
The error makes totally sense to me, but I've no clue how I can get a actual user reference to update the profile, any idea?

It looks like you're assuming that verifyIdToken() generates a promise that contains a User object. That's not the case here. According to the API docs, it provides a DecodedIdToken object. That object contains a uid property with the UID of the user represented by the token you passed to it.
If you want to get a UserRecord object from there, you can call admin.auth().getUser(uid) with that UID. However, that won't help you update the user's profile.
If you want to update the profile for a given UID, you can call admin.auth().updateUser(uid, properties).

Related

React doesn't recognize user attributes in Amplify app

I built an Amplify app with Cognito user pools for authentication/authorization. I am now trying to retrieve user attributes using Auth.currentAuthenticatedUser() . The example code they have (which works well) is the following:
import { Auth } from 'aws-amplify';
Auth.currentAuthenticatedUser({
bypassCache: false
})
.then((user) => console.log(user))
.catch((err) => console.log(err));
Here, the console.log(user) logs all of the current user data, as expected. I would like to now capture that data (or at least individual attributes of it) in a variable that I can use later on. However, if I try to define a variable using user it gives me an undefined error.
Here is an example of what I have tried and the error generated:
Code:
Auth.currentAuthenticatedUser({
bypassCache: false
})
.then((user) => console.log(user))
.catch((err) => console.log(err));
let userData = user;
Error:
'user' is not defined no-undef
I have also tried const and var but no matter what, it does not recognize user . I don't understand how this is possible since it is successfully logged two lines above. Any ideas would be appreciated!
I was able to store the values within a const by putting it inside of a try/catch block:
try {
const user = await Auth.currentAuthenticatedUser();
const userGroup = user;
console.log(user);
} catch (err) {}
In my case, I only wanted the user group, so I actually narrowed it down to that parameter:
const userGroup = user.signInUserSession.accessToken.payload["cognito:groups"]

How can I get a value from the JWT header into a variable in nodejs?

I am making an API server where I can login and see some information. Whenever I log in I get a JWT token which contains my username. I want to store this username in a variable whenever I want to use it. This is the code I use to verify my token when I want to enter certain webpages.
import jwt from "jsonwebtoken";
function authenticateToken(req, res, next) {
const authHeader = req.header("access-token");
if (!authHeader) return res.sendStatus(401);
jwt.verify(authHeader, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
export default authenticateToken;
It checks if the header contains a JWT token. If so it verifies it. Then at the bottom the user gets retrieved, but I dont know how to get this value.
On my routes I secure them like this:
router.get("/", authenticateToken, getData);
within the getData method im displaying data from a mysql database. I want to add a check to see if my username is equal to the data in getData (since you can only see certain data).
In getData i get my data like this:
connection.query(
"SELECT * FROM data WHERE userid = ?", [user.username],
(err, rows) =>
On the [user.username] spot I want to retrieve the username within the JWT token. I want to do this using a method, but I cant seem to get it. How can I get my username?
You could try to change your code a little bit to pass the request to the getData function, as you store the authenticated user within the request.
Try something like this:
router.get("/", authenticateToken, async (req, res) => {
getData(req);
});

Why deleteOne & findById of mongoose work on deleted id

Currently developing an API with nodejs that communicates with a MongoDB database, I noticed a special behavior after deleting a document.
Indeed, my API has several endpoints that allow to retrieve all the animals in the database, to retrieve a specific one using the corresponding id or to delete a specific one, again using the id of the document to delete.
The results I don't understand happen once a document is deleted. Indeed, as you can see in the picture below, when I delete the document of the animal called "Johnny" the queries to find it via its id or to delete it via the same ID continue to work, even if the get returns nothing and the deletion indicates that no operation has been performed.
Personally I expected the same behavior as if I passed a wrong id for a deletion (visible below), but if the id has already been assigned in the database the queries work even after a deletion.
Does MongoDB have a "cache" of deleted documents in order to perform a rollback in case of unwanted deletion?
You will find below the different endpoints that use find, deleteOne & findById
exports.getAllAnimal = (req, res, next) => {
Animal.find().sort({'customer' : 1})
.then(animals => res.status(200).send(animals))
.catch(error => res.status(400).send({ error: error.message }));
};
exports.getOneAnimal = (req, res, next) => {
Animal.findOne({ _id: req.params.id })
.then(animal => res.status(200).send(animal))
.catch(error => res.status(400).send({ error: error.message }));
};
exports.deleteAnimal = (req, res, next) => {
Animal.deleteOne({ _id: req.params.id })
.then(thing => res.status(200).send({ message : 'Animal successfully deleted'}))
.catch(error => res.status(400).send({ error: error.message }));
};
MongoDB does not cache deleted id anywhere.
The thing is that when you said I passed a wrong id for a deletion ... you are passing an id with the same length but not in the required format. That's why Mongoose is throwing you an error.
However, if you follow the id structure of MongoDB to create an id that does not exist in the database and run an operation against it, MongoDB will still return you with success and an empty result.
Try using 5ea08034385a46666b05020f and run the .findById() query function against it. It's going to return you with a success an empty result.
The success only means that the operation is successful, but it doesn't necessarily mean that it actually finds something in the database.
I don't have access to your database, so the id is generated randomly but following the MongoDB ObjectId rules below:
The 12-byte ObjectId value consists of:
a 4-byte timestamp value, representing the ObjectId’s creation, measured in
seconds since the Unix epoch
a 5-byte random value
a 3-byte incrementing counter, initialized to a random value
Generate arbitrary MongoDB ObjectId:
https://observablehq.com/#hugodf/mongodb-objectid-generator

Firebase: Why am I getting Firebase ID Tokens twice?

Question
From the following situations, I could see two different tokens:
After completing the sign-up, I get the first Firebase ID Token.
I'm getting a new JWT when I come back to my app after completely signing out.
What I've found
const app = express();
app.use((req, res, next) => {
if (!req.headers.authorization)
return res.status(403).json({ message: 'Missing Authorization Header' });
const jwt = req.headers.authorization.trim();
return admin.auth().verifyIdToken(jwt).then((decodedToken) => {
const uid = decodedToken.uid; // Exists
const displayName = decodedToken.name; // No displayName, object Undefined
const photoURL = decodedToken.picture; // No photoURL, object Undefined
next();
});
});
Even though I've updated the user's default profile by calling the function below, it seems like ID token does not contain user's displayName and photoURL.
initializeUserProfile(name: string, photoURL: string) {
let data = {
displayName: name,
photoURL: photoURL
};
this.afAuth.auth.currentUser.updateProfile(data).then(() => {
this.getUsersRef(this.currentUserId).update(data); // Save data to firestore
}).catch((err) => console.log(err));
}
Note: After the sign-out and successfully logged into the app, the token's length gets much longer than the previous token. Also, it does contain displayName and photoURL as well.
I've also posted my related issue here, and it seems like the token causes the problem.
Why am I getting a new token? And how can I resolve this issue?
To get a new ID token with the latest claims after you update the profile via updateProfile, you can simply force token refresh by calling: currentUser.getIdToken(true).
Note, naturally on token refresh when the token is expired, the new token will automatically pick up the latest claims with the profile changes. To get this immediately, you can force refresh.

Firebase getToken() TypeError: Cannot read property

I'm trying to get the token of my currently signed in user of my website. However, javascript cannot get the value for me. I think there are 2 problems here:
When I'm getting Auth.currentUser at start, I get this error of "TypeError: Cannot read property 'getToken' of null". But when I type Auth.currentUser.getToken() in the console, the object with the token actually shows up.
What getToken() returns to me is a promise object with its key 'ea' containing the value of the token. but when I do Auth.currentUser.getToken().ea it gets me 'null'. How can I retrieve the token directly from the object?
Thanks!
My code of retrieving the token:
var Auth = firebase.auth()
var token = Auth.currentUser.getToken()
This screenshot might be helpful:
According to the documentation of firebase.User:getIdToken():
Returns a JWT token used to identify the user to a Firebase service.
Returns the current token if it has not expired, otherwise this will refresh the token and return a new one.
The method returns a promise, since it may require a round-trip to the Firebase servers in case the token has expired:
Auth.currentUser.getIdToken().then(data => console.log(data))
Or in more classic JavaScript:
Auth.currentUser.getIdToken().then(function(data) {
console.log(data)
});
Log output:
ey...biPA
Update: to ensure that the user is signed in before getting the token, run the above code in an onAuthStateChanged listener:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
user.getIdToken().then(function(data) {
console.log(data)
});
}
});
Here is a sample on how to get the id token using NodeJS
var firebase = require('firebase')
firebase.initializeApp({
apiKey:*********
databaseURL:*********
})
var customToken = *********
firebase.auth().signInWithCustomToken(customToken).catch(function(error) {
var errorMessage = error.message
console.log(errorMessage)
})
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
firebase.auth().currentUser.getToken().then(data => console.log(data))
} else {
console.log('onAuthStateChanged else')
}
})

Categories