How to use Facebook token obtained through Firebase authentication appropriately? - javascript

I am trying to get a person's first name and last name when the person would like to sign up through Facebook, but wondering if there can be some security issue.
Based on the document from Firebase, the answer from Stack Overflow, and the explanation about parameters from Facebook website, I wrote the following codes:
firebase.auth().getRedirectResult().then(function(result) {
var token = result.credential.accessToken;
FB.api('/me', {fields: 'last_name', access_token: token}, function(response) {
console.log(response);
})
})
My main concern is that according to Facebook, it says:
One parameter of note is access_token which you can use to make an API call with a Page access token. App access tokens should never be used in this SDK as it is client-side, and your app secret would be exposed."
It looks like I cannot use this approach to get a user's first and last name.

Starting with Firebase 4.0.0, additional IdP data will be directly returned in the result of type UserCredential. You shouldn't need to make an additional API call to Facebook to get data like first/last name:
firebase.auth().getRedirectResult().then(function(result) {
if (result.user) {
// Additional user info like first name, last name,
// Facebook account url, gender, etc.
console.log(result.additionalUserInfo.profile);
// Facebook access token returned in the process
// for the scopes requested.
console.log(result.credential.accessToken);
}
});

Related

How To Setup Custom Claims In My React Website For a Login Page

I want to set up custom claims to a certain number of users let's say 5 users would be admins on my website. I want these 5 users to be able to log in through the login page which would redirect them to the dashboard.
but I still don't fully understand the concept of the custom claims and how to use them and firebase documentation is limited with examples.
In their example they show that I can pass a uid that I want to assign a custom claim to, but how is this supposed to be a variable when i want certain users uid's from my firestore database Users collection to be admins and have a custom claim, in other words, where would I put this code or how would I assign a custom claim to more than one user at a time and how and where would this code be executed.
if anyone can give me an example of how I would make this work.
here is what I did:
created a firebaseAdmin.js file:
var admin = require("firebase-admin");
// lets say for instance i want these two users to be admins
//2jfow4fd3H2ZqYLWZI2s1YdqOPB42
//2jfow4vad2ZqYLWZI2s1YdqOPB42 what am i supposed to do?
admin
.auth()
.setCustomUserClaims(uid, { admin: true })
.then(() => {
// The new custom claims will propagate to the user's ID token the
// next time a new one is issued.
});
I honestly don't know what to do from here.
Custom Claims can only be set from a privileged server environment via the Firebase Admin SDK. The easiest ways are either using a Node.js script (running the Admin SDK) or a Cloud Function (which also uses the Admin SDK).
Let's look at the example of a Callable Cloud Function that you call from your front-end (and in which you could check the UID of the user who is calling it, i.e. a Super Admin).
exports.setAdminClaims = functions.https.onCall(async (data, context) => {
// If necessary check the uid of the caller, via the context object
const adminUIDs = ['2jfow4fd3H2ZqYLWZI2s1YdqOPB42', '767fjdhshd3H2ZqYLWZI2suyyqOPB42'];
await Promise.all(adminUIDs.map(uid => admin.auth().setCustomUserClaims(uid, { admin: true })));
return { result: "Operation completed" }
});
A Node.js script would be similar:
#!/usr/bin/node
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.cert(".....json") // See remark on the private key below
});
const adminUIDs = ['2jfow4fd3H2ZqYLWZI2s1YdqOPB42', '767fjdhshd3H2ZqYLWZI2suyyqOPB42'];
Promise.all(adminUIDs.map(uid => admin.auth().setCustomUserClaims(uid, { admin: true })))
.then(() => {
console.log("Operation completed")
})
You must generate a private key file in JSON format for your service account , as detailed in the doc.
Then, when the Claims are set, you can access these Claims in your web app, and adapt the UI (or the navigation flow) based on the fact the user has (or not) the admin claim. More detail here in the doc.

admin.auth().currentUser; returning undefined in Cloud Function

I am trying to create a function that, when a device is registered in the app, will attach this device uid to the uid of the signed-in user who registered the device (this is in another firestore collection that is automatically created when a user registers).
Here is my code:
exports.addDeviceToUser = functions.firestore.document('device-names/{device}').onUpdate((change, context) => {
const currentUser = admin.auth().currentUser;
const deviceName = context.params.device;
var usersRef = db.collection('users');
var queryRef = usersRef.where('uid', '==', currentUser.uid);
if (authVar.exists) {
return queryRef.update({sensors: deviceName}).then((writeResult => {
return console.log('Device attached');
}));
} else {return console.log('Device attachment failed, user not signed in');}
});
I am consistently getting this error: "TypeError: Cannot read property 'uid' of undefined." Obviously I am not able to access the auth information of the current user. Why?
The Admin SDK doesn't have a sense of current user. When you say admin.auth(), you're getting back an Auth object. As you can see from the API docs, there is no currentUser property on it. Only the Firebase client SDK has a sense of current user, because you use that to get the user logged in.
If you need the client app to tell Cloud Functions code work with the user's identity, you have to send it an ID token from the client, and verify it on the server. Then the server can know who the end user is, and perform actions on their behalf. Typically you do this with an HTTP type trigger. Callable functions transmit this data automatically between the client and server, but you can do it manually yourself using code that works like this sample.
Right now, Firestore triggers don't have immediate access to the end user that made a change in the database. However, if you use the Auth UID of the user as the key of the document, and protect that document with security rules, you can at least infer the UID of the user based on the changes they make to the document by pulling it out of the id of the document that changed.
Because, by design, Cloud Functions executes on the back end and do not hold any information on which user was authenticated when adding/modifying the data in the database.
When writing the data in the 'device-names/{device}' document (from your app), you could include an extra piece of data which is the uid of the current user.

Retrieving public profile from Facebook with Firebase and AngularJS

So, I've been using Firebase in my AngularJS/Ionic project to access my app with Facebook authentication.
The authentication goes fine, it retrieves some data (Display_name, email, urid, url photo, etc.), but I need more.
I need to get the first name and last name for my project, because I'll need to work with it. When the person accepts to share the information it says that she's sharing her public profile, but the data that comes doesn't have what Facebook documentation says that public profile provides.
I used Firebase documentation to program this. There's a part where it says to use addScope to add what you want, public profile is asked by default, but I added it anyway. (I can't post the link, StackOverflow says that my reputation is too low).
$scope.FBLogin = function (){
firebase.auth().signInWithPopup(provider).then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
var profile = result.user.public_profile;
console.log("success")
console.log(result);
console.log(user);
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
};
Log here:
So, since I don't want to have to use the "display name". as people sometimes don't use their real names there.
Does anyone know how to retrieve that information using Firebase and AngularJS?
Currently this is not supported by Firebase. You have to make the extra api call to Facebook to get that data.
result.credential.accessToken contains the Facebook access token. Using that access token, you can get facebook profile data. Here is an example how to do that with facebook:
How to get user profile info using access token in php-sdk
AJAX GET 'https://graph.facebook.com/me?access_token=' + result.credential.accessToken
For people looking for how to do it in AngularJS or how do you filter what you want this is how i did it using the information bojeil gave me!(Thank you again!)
var token = result.credential.accessToken;
var user = result.user;
$http.get('https://graph.facebook.com/v2.5/me? access_token='+token+'&fields=id,name,first_name,last_name,email')
.success(function(jsonService){
$scope.user.firstName= jsonService.first_name;
$scope.user.lastName= jsonService.last_name
$scope.user.email = jsonService.email;
});

how to nest access tokens in javascript safely?

FB.api({user-id},
{
"fields":"context",
"access_token": anAccessToken
}, function (response) {
console.log(response);
})
I am currently getting mutual friends via the context object. But in order for that to happen, I need to pass both the app_scoped_userid and my accesstoken from Oauth.
I feel uneasy putting these two strings in my client, since together anyone can use them to query any information the user has allowed my app permission to use.
Is there a better solution? (I have been contemplating moving the graph call onto the server, but that works against the light server-heavy client structure I am trying to achieve.)
Am I right to be worried?
I don't think that it's correct how you're using this functionality. According to https://developers.facebook.com/docs/graph-api/reference/v2.2/user.context/mutual_friends you should be able to run the following request:
/{friend_id}?fields=context{mutual_friends}
The Access Token (from the currently logged-in User) should be handled transparently by the JS SDK. I see no need to specify it for the request:
FB.api('/{friend_id}?fields=context{mutual_friends}', function(response) {
console.log(response);
});
To the the {friend_id}, you'll need to query /me/friends first for the current User, and select a specific friend.

Signup with Facebook JS SDK

I'm trying to create a signup functionality with Facebook JS SDK, But i got different type of records, than i search a lot and come to know that Facebook update his app policy's, they release v2.0 for apps.
Now it sending different response on login
Object {authResponse: Object, status: "connected"}
authResponse: Object
accessToken: "CAATZCeMqNYsABADVG3lHL1WYJiwnZASJIBzUtkfB4MFyFUC21g6myDeAP6WDSKkd8ZAnggffW5sIJzSDqmqxxvRgdeT7MKRXJ0L8Logg57PYwawEBSbgqz9I5qGU9Oo7uvaRN5MupjCfvo5w4bfCDZA5uvMkg7AK8DbwhXW4WoGHZBgG6EsmDDWZCnbVpUxWUZD"
expiresIn: 4562
signedRequest: "GXGqWXN9C5IzSy6jf2NOOQK7-ZK9JisKBCLEBHbaoIc.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImNvZGUiOiJBUUE5c21GSWZ1dXoxMnpvNVV0MGdYYXNXclI1blJXZXh1NElGWHFFMHhnUDM3T0pScUJyaDhZeEo2YWt5aHlJYXUzc3UyU2hhZVczUzh1aHRheWJGX3N3aWtfSmVfUDRwallOeV9IX1JpTEs2ZWZKNlpETDQ5MC1OVUxKSzN4SWw2QmtfVXJER2ZrVE1uV1haZFY3LU02Y19xMjRwWjJUOEo2anB6djNGQ0Z0YUs5bW5fMVVobThycjRlVmlQOVVtVVNMZXA5NTg1X1ZhSHg2YkUyTEFBMUl3OUdfQXJnb2JRSldQaERXczlTSDdONzNzS1dlakQ3MDNsTmhpblhjbUt0RXU1NmpvTnVMODhvME9ZUXVtVEFfbzF4SEJ5YndSbDU4ekVrWEpMdVUtVFZfejY5UW9KekFMeFRCekNBUHBXcEQtVzUyVHlKd0tJNjBMTU5Qbjg0bCIsImlzc3VlZF9hdCI6MTM5OTI3NTgzOCwidXNlcl9pZCI6IjEwMDAwMDAxNTU5MzEwNyJ9"
userID: "100000015593107"
__proto__: Object
status: "connected"
__proto__: Object
}
as in last SDK we get email using
response.email
but in new one we got only userID which is also app specific and
response.authResponse.signedRequest
So i search how we can extract the "signedRequest" because i think the rest value surely encrypted in this code ..
So i used
$signed_request= $_POST['maindata'];
if (isset($signed_request))
{
$data_signed_request = explode('.', $signed_request); // Get the part of the signed_request we need.
$jsonData = base64_decode($data_signed_request['1']); // Base64 Decode signed_request making it JSON.
$objData = json_decode($jsonData, true); // Split the JSON into arrays.
}
print_r($objData);
but its again send me
Array
(
[algorithm] => HMAC-SHA256
[code] => AQA9smFIfuuz12zo5Ut0gXasWrR5nRWexu4IFXqE0xgP37OJRqBrh8YxJ6akyhyIau3su2ShaeW3S8uhtaybF_swik_Je_P4pjYNy_H_RiLK6efJ6ZDL490-NULJK3xIl6Bk_UrDGfkTMnWXZdV7-M6c_q24pZ2T8J6jpzv3FCFtaK9mn_1Uhm8rr4eViP9UmUSLep9585_VaHx6bE2LAA1Iw9G_ArgobQJWPhDWs9SH7N73sKWejD703lNhinXcmKtEu56joNuL88o0OYQumTA_o1xHBybwRl58zEkXJLuU-TV_z69QoJzALxTBzCAPpWpD-W52TyJwKI60LMNPn84l
[issued_at] => 1399275838
[user_id] => 100000015593107
)
I'm wondering how we can get the email address , Please if you have some idea please let me know
You can use the acquired access_token and use the Facebook API endpoint GET /me and pass the access_token the response of the said endpoint will allow you to obtain the email address given that the email address being associated to the Facebook is account is still valid.

Categories

Resources