Firebase authWithCustomToken throwing an error instead of calling callback? - firebase

I am following the example in the docs:
ref.authWithCustomToken(authToken, function(error, authData) {
if (error) {
console.log("Authentication Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
});
If I pass an invalid token to authWithCustomToken (e.g. authToken is undefined) , it throws an Error, rather than passing an error code to the callback. In other words, neither console.log is executed, but this error is thrown:
First argument must be a valid credential (a string).
Wrapping it in try catch solves the problem easily enough, but I didn't see any mention in the docs. Is it the intended behaviour?
In my use-case the token is passed through a url, so an undefined parameter is a possible error condition.

From firebase-debug.js:
if (!goog.isString(cred)) {
throw new Error(fb.util.validation.errorPrefix(fnName, argumentNumber, optional) + "must be a valid credential (a string).");
}
What probably happened:
You passed a non-string value as authToken so the error not happened in the Firebase (server) side, it happened in the client side (your side) so it will be not reported on the callback function but as Javascript exception in your code.
Possible workaround (I don't know why, but if you want)
If you want to pass a variable as authToken and it could not be a string, and you still want to get the "Wrong credentials" error, instead of type validation, then you need to force string conversion using:
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
var numberAuthToken = 212312312312312; // number
var stringAuthToken = String(numberAuthToken);
ref.authWithCustomToken(stringAuthToken, function(error, authData) {
if (error) {
console.log("Authentication Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
});
But it not makes sense for me. :)

Related

Firebase Function Get Single Value From Database

I want to get a single value from Firebase Database within Firebase function. However, the Promise never returns and the chained method never executes. Here is the method that fetches a value from the database
function getFcmToken(username){
return admin.database().ref('tokens/{username}/fcmToken').once('value').then(snap => {
if(snap.exists()){
const token = Object.keys(snap.val());
console.log("FCM Token", token);
return token;
}
return [];
});
}
The above method was supposed to return a token, but I am not sure it is, so the method below does not get executed.
function sendNotification(keyword, username){
return getFcmToken(username).then(token => {
if(token.length > 0){
//Notification Detail
let payload = {
data:{
keyword: keyword
}
};
return admin.messaging().sendToDevice(token, payload);
}
});
}
In the console log, all I see is Promise pending.
How can I update the code above to return a single value, it appears it is returning an array?
Thanks
Your database ref path is wrong. You might wanted to replace username in path, but single quoted won't do that.
Firebase is listening on tokens/{username}/fcmToken, which doesn't exists. Hence on value event will not be triggered and so downline callback will not be executed.
You can use Template literals for building dynamic strings.
Try ref path as
`tokens/${username}/fcmToken`
Code:
function getFcmToken(username){
return admin.database().ref(`tokens/${username}/fcmToken`).once(...)
}

meteorjs get data returned from server callback

In meteor im trying to insert a new document by making a Meteor.call from the client. Everything is working ok, except that I want to return the id of create document to the client, so that i can redirect to the proper url.
I have something similar to this (client):
Meteor.call('scenarioCreate', scenarioObj, function(err, response) {
if(err) {
console.warn(err);
return;
}
console.info(response);
});
On server:
Meteor.methods({
'scenarioCreate': function(scenarioObj) {
Scenarios.insert( scenarioObj, function(err, id) {
console.info("new id: "+id);
if (err) {
console.warn(err);
throw new Meteor.Error(404, 'Something went wrong');
}
return id;
});
}
});
From the server side i get the console log "new id: DDaq4aWsGf3fxG7RP", but I should get that same value on the client on the "response" value, but I always get undefined.
Can anybody explain to me why or what I am doing wrong.
Meteor.methods doesn't wait for your callback. Try this:
On server:
Meteor.methods({
'scenarioCreate': function(scenarioObj) {
var newId = Scenarios.insert(scenarioObj);
return newId;
}
});
To catch any error, use try/catch
Note: If you still want to use callback, checkout fibers/future.
Your first error is that you are returning id inside the callback for insert. That doesn't do anything. Then your second is not knowing that methods are synchronously executed. That would mean that you could only use the information available inside the callback using Meteor.wrapAsync. But that's besides the point. The insert function returns the new _id. Meaning you can do this:
Meteor.methods({
'scenarioCreate': function(scenarioObj) {
return Scenarios.insert( scenarioObj );
}
});

Firebase authWithCustomLogin: undefined is not a function

I am trying to set up authentication for admin users for an angular app. I have so far created the following code:
$http.post('/customAuth/adminBDauth.php', {email: email, password:password}).success(function(data){
var refAuth = new Firebase('https://<firebase-ref>');
refAuth.authWithCustomToken(data, function(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Login Succeeded!", authData);
}
});
});
However the following error is occurring - TypeError: undefined is not a function (referring to authWithCustomToken)
I know that the Firebase ref is fine because I have logged its value to check. I also know that the firebase token is being generated (though aware that doesn't appear to be the problem here in any event).
I am stumped as to why this doesn't work and can't think of any other tests to run. Anyone had a similar problem or know how I might proceed?
Thanks
Makesure you include dependency "$firebaseAuth" as it says here
app.controller("SampleCtrl", ["$scope", "$firebaseAuth",
function($scope, $firebaseAuth) {
var ref = new Firebase("https://<your-firebase>.firebaseio.com/");
var auth = $firebaseAuth(ref);
auth.$authWithOAuthPopup("facebook").then(function(authData) {
console.log("Logged in as:", authData.uid);
}).catch(function(error) {
console.error("Authentication failed: ", error);
});
}
]);
As well as installing angularfire

Extending the Meteor loginWithPassword method

I may be totally off line here, but I'm trying to extend the loginWithPassword method in Meteor to handle only returning users with a few parameters set in their profile.
I'm creating the users fine and once created they login as that user type and all is good, but, when I try and login again I hit a wall.
I've tried implementing my own login handler as follows...
Accounts.registerLoginHandler(function(loginRequest) {
console.log("Got to Accounts.registerLoginHandler");
console.log(loginRequest);
var userId = null;
var user = Meteor.loginWithPassword(loginRequest.email, loginRequest.password, function(error){
if(error !== undefined){
setAlert('error', 'Error in processing login. ' + error.reason + '.');
}
});
var userWithType;
if(user){ // we have the right username and password
console.log("Found a user and logged them in");
userWithType = Meteor.users.findOne({'id': user._id, 'profile.type': loginRequest.type});
}
if(userWithType){
console.log("Found User of that type")
userId = user._id;
}
console.log("UserId", userId);
return {
id: userId
}
});
But am getting an error when I get to this code that says
Got to Accounts.registerLoginHandler
{ email: 'blah2#blah', password: 'blha', type: 'user' }
Exception while invoking method 'login' TypeError: Object #<Object> has no method 'loginWithPassword'
at app/server/login.js:8:23
at tryAllLoginHandlers (app/packages/accounts-base/accounts_server.js:53:18)
at Meteor.methods.login (app/packages/accounts-base/accounts_server.js:73:18)
at maybeAuditArgumentChecks (app/packages/livedata/livedata_server.js:1367:12)
at _.extend.protocol_handlers.method.exception (app/packages/livedata/livedata_server.js:596:20)
at _.extend.withValue (app/packages/meteor/dynamics_nodejs.js:31:17)
at app/packages/livedata/livedata_server.js:595:44
at _.extend.withValue (app/packages/meteor/dynamics_nodejs.js:31:17)
at _.extend.protocol_handlers.method (app/packages/livedata/livedata_server.js:594:48)
at _.extend.processMessage.processNext (app/packages/livedata/livedata_server.js:488:43)
I'm obviously missing a this pointer or something like that, but don't know enough about this framework to know if I'm totally off track here even trying to get this to work.
Ta
P.
I am not too familiar with it but from http://docs.meteor.com, Meteor.loginWithPassword () can only be called on the client. You have written it into the server side code from the tutorial.
That is throwing the error you see. If you move it to the client you will also see that it only returns to the callback function so your variable user will remain undefined.
Meteor.user().profile is available on the client so you can just check the type there in the callback of loginWithPassword to check the information at login.

Handlings exceptions on the server, customising the fail argument on the client

I'm hoping to be able to customise the error objects that are passed to the client if an exception occurs on the server.
I'm using the 'then' function on the client to handle success and failure:
hub.server.login(username, password).then(function(result) {
// use 'result'
}, function(error) {
// use 'error'
});
If the login succeeds, 'result' is the return value of the Login method on the server. If the login fails, I throw an exception of 'CustomException'. This is an exception with a 'Code' property.
if (!IsValidLogin(username, password))
throw new CustomException { Code: "BADLOGIN", Message: "Invalid login details" };
If I have detailed exceptions enabled, the 'error' argument on the client is 'Invalid login details' - the Message property of the exception.
Is there any way I can selectively change the error result from a string to a complex object? i.e. if 'CustomException' is thrown in a hub method, return a {Code:[...], Message:[...]} object for the client-side fail handler?
This should demonstrate what I'd like to see on the client:
hub.server.login(username, password).then(function(userInfo) {
alert("Hello " + userInfo.Name);
}, function(err) {
if (err.Code === "BADLOGIN.USERNAME")
alert("Unrecognised user name");
else if (err.Code === "BADLOGIN.PASSWORD");
alert("Invalid password");
else
alert("Unknown error: " + err.Message);
});
(Note the 'Code' and 'Message' properties on 'err').
When you call MapHubs with EnabledDetailedErrors set to true as follows:
RouteTable.Routes.MapHubs(new HubConfiguration { EnableDetailedErrors = true });
you will receive your Exception's Message string as the parameter to your fail handler.
I see that you have already figured this out, but I'm including the server side code to enable detailed errors for anyone else who might find this question later.
Unfortunately there is no easy way to send a complex object to the fail handler.
You could do something like this though:
if (!IsValidUsername(username))
{
var customEx = new CustomException { Code: "BADLOGIN.USERNAME", Message: "Invalid login details" };
throw new Exception(JsonConvert.SerializeObject(customEx));
}
if (!IsValidPassword(username, password))
{
var customEx = new CustomException { Code: "BADLOGIN.PASSWORD", Message: "Invalid login details" };
throw new Exception(JsonConvert.SerializeObject(customEx));
}
Then on the client:
hub.server.login(username, password).then(function(userInfo) {
alert("Hello " + userInfo.Name);
}, function(errJson) {
var err = JSON.parse(errJson);
if (err.Code === "BADLOGIN.USERNAME")
alert("Unrecognised user name");
else if (err.Code === "BADLOGIN.PASSWORD");
alert("Invalid password");
else
alert("Unknown error: " + err.Message);
});
I know this is ugly, but it should work.

Resources