I've been developing an app in Unity for the past two years and only now realized that my phone authentication didn't work correctly. This is because I'm developing on Android and therefore I've always only seen the results of "verificationCompleted" and not codeSent.
In other words, putting the SMS code in manually doesn't work. It says that the credential is invalid. IT ISN'T! The code is right. The thing is, that I copied my code over to another project, and then it worked perfectly. Therefore it's probably nothing wrong with my code. What could've happened here? Also, everything worked fine, until I was supposed to verify the code itself. I got the SMS etc.
When can you get the error, invalid credential, when the code isn't wrong?
Feels like I've tried everything!
Thanks in advance for any help!
Here's some pictures of my code as well. Some stuff has nothing to do with the authentication, but yeah...
public void VerifyPhoneNumber(string _phoneNumber)
{
Debug.Log(String.Format("Auth is {0}, AuthenticationController is {1} and GameController is {2}.", auth, authenticationController, null));
var phoneAuthProvider = Firebase.Auth.PhoneAuthProvider.GetInstance(auth);
phoneAuthProvider.VerifyPhoneNumber(_phoneNumber, phoneAuthTimeoutMs, null,
verificationCompleted: (cred) =>
{
Debug.Log("Verification Completed");
MutualUiController.mutualUI.loadingPanel.gameObject.SetActive(false);
auth.SignInWithCredentialAsync(cred).ContinueWith(HandleSignInResult);
},
verificationFailed: (error) =>
{
Debug.Log("Verification Failed" + error);
},
codeSent: (id, token) =>
{
Debug.Log("Verification Code Sent");
phoneAuthVerificationId = id;
Debug.Log("ID: " + id + ", Token: " + token.ToString());
if (SceneController.currentScene == Scene.AuthenticationPage)
{
MutualUiController.mutualUI.loadingPanel.gameObject.SetActive(false);
Transform panel = GameObject.Find("AuthPageUI").GetComponent<AuthPageUI>().verificationPanel;
panel.gameObject.SetActive(true);
}
},
codeAutoRetrievalTimeOut: (id) =>
{
Debug.Log("Code Auto Timeout");
});
}
//verificationCompleted: (cred) =>
// {
// //Debug.Log("Verification Completed");
// //MutualUiController.mutualUI.loadingPanel.gameObject.SetActive(false);
// //auth.SignInWithCredentialAsync(cred).ContinueWith(HandleSignInResult);
// },
public void VerifyRecievedPhoneCode(string recievedCodeInput)
{
var phoneAuthProvider = Firebase.Auth.PhoneAuthProvider.GetInstance(auth);
var cred = phoneAuthProvider.GetCredential(phoneAuthVerificationId, recievedCodeInput);
auth.SignInWithCredentialAsync(cred).ContinueWith(HandleSignInResult);
}
Related
I am new to AppMaker but I have developer experience.
The application is a Project Tracker Application
What I expect to happen: When creating a project the user uses a User Picker to select the users associated with that project. When the project is created I want to email the users associated with that project.
The issue: On clicking the Add button addProject(addButton) client script function is called.
Inside this function sendEmailToAssignees(project, assignees) is called which should reach out to the Server script and run the notifyAboutProjectCreated(project, assignees) but that is not happening.
Things to know: With logging I never reach 'Trying to send email' so I seem to never reach my server script. Also, On client script when I comment out sendEmailToAssignees function everything runs smooth. I have looked at this documentation as a resource so I feel my implementation is okay. https://developers.google.com/appmaker/scripting/client#client_script_examples
The final error message I get is:
Failed due to illegal value in property: a at addProject
(AddProject:110:24) at
AddProject.Container.PanelAddProject.Form1.Spring.ButtonAdd.onClick:1:1
Am I missing something here? Any help would be greatly appreciated. Thank you!
Client Script
function sendEmailToAssignees(project, assignees) {
google.script.run
.withSuccessHandler(function() {
console.log('Sending Email Success');
}).withFailureHandler(function(err) {
console.log('Error Sending Email: ' + JSON.stringify(err));
})
.notifyAboutProjectCreated(project, assignees);
}
function addProject(addButton) {
if (!addButton.root.validate()) {
return;
}
addButton.datasource.createItem(function(record) {
var page = app.pages.AddProject;
var pageWidgets = page.descendants;
var trainees = pageWidgets.AssigneesGrid.datasource.items;
var traineesEmails = trainees.map(function(trainee) {
return trainee.PrimaryEmail;
});
record.Assignee = traineesEmails.toString();
var assignees = traineesEmails.toString();
var project = record;
updateAllProjects(record);
console.log('update all projects done');
sendEmailToAssignees(project, assignees);
console.log('Send Email done');
if (app.currentPage !== app.pages.ViewProject) {
return;
}
gotoViewProjectPageByKey(record._key, true);
});
gotoViewProjectPageByParams();
}
Server Script
function notifyAboutProjectCreated(project, assignees) {
console.log('Trying to send email');
if (!project) {
return;
}
var settings = getAppSettingsRecord_()[0];
if (!settings.EnableEmailNotifications) {
return;
}
var data = {
appUrl: settings.AppUrl,
assignee: project.Assignee,
owner: project.Owner,
startDate: project.StartDate,
endDate: project.EndDate,
jobType: project.Type,
jobId: project.Id
};
// Email Subject
var subjectTemplate = HtmlService.createTemplate(settings.NotificationEmailSubjectJob);
subjectTemplate.data = data;
var subject = subjectTemplate.evaluate().getContent();
// Email Body
var emailTemplate =
HtmlService.createTemplate(settings.NotificationEmailBodyJob);
emailTemplate.data = data;
var htmlBody = emailTemplate.evaluate().getContent();
console.log('About to send email to:', assignees);
sendEmail_(null, assignees, subject, htmlBody);
}
The reason you are getting this error is because you are trying to pass the client "project record" to the server. If you need to access the project, then pass the record key to the server and then access the record on the server using the key.
CLIENT:
function sendEmailToAssignees(project, assignees) {
var projectKey = project._key;
google.script.run
.withSuccessHandler(function() {
console.log('Sending Email Success');
}).withFailureHandler(function(err) {
console.log('Error Sending Email: ' + JSON.stringify(err));
})
.notifyAboutProjectCreated(projectKey , assignees);
}
SERVER:
function notifyAboutProjectCreated(projectKey, assignees) {
console.log('Trying to send email');
var project = app.models.<PROJECTSMODEL>.getRecord(projectKey);
if (!project) {
return;
}
//Rest of the logic
}
The project record object in the client is not the same as the project record object in the server; hence the ilegal property value error.
I want to add Firebase project through Firebase Management Api. So for that. I made project on Google Cloud Platform console. And created service account with permission as a owner.
I tried to read and create project throw google api explorer for addFirebase and it works. But when i try to do the same through my code it read availableProject successfully and give output as
{
"projectInfo": [
{
"project": "projects/firebase-api-238012",
"displayName": "Firebase-Api"
}
]
}
but when i try to add project it give me this error
{
"error": {
"code": 403,
"message": "The caller does not have permission",
"status": "PERMISSION_DENIED"
}
}
I don't know why its is not creating project. What other permission it needs. And why it allowed to me read available projects first.
here is how i am trying to add my project.
jwt.js
const { google } = require('googleapis');
var serviceAccountJwt = require('./Firebase-Api-b0e41b85ad44.json');
exports.connect = async () => {
return new Promise((resolve, reject) => {
// scope is based on what is needed in our api
const scope = ['https://www.googleapis.com/auth/firebase', 'https://www.googleapis.com/auth/cloud-platform'];
// create our client with the service account JWT
const { client_email, private_key } = serviceAccountJwt;
const client = new google.auth.JWT(client_email, null, private_key, scope, null);
// perform authorization and resolve with the client
return client.authorize((err) => {
if (err) { reject(err) }
else {
resolve(client)
};
});
});
}
index.js file
const { google } = require('googleapis');
const request = require('request');
const { connect } = require('./jwt');
const availableProjects = 'https://firebase.googleapis.com/v1beta1/availableProjects';
async function getAccessToken() {
let client = await connect();
let accessToken = await client.getAccessToken();
let res = await getProjects(accessToken.token)
}
getAccessToken().catch(err => {
console.log(JSON.stringify(err))
})
const bodys = {
"timeZone": "America/Los_Angeles",
"locationId": "asia-south1",
"regionCode": "US"
}
async function getProjects(accesstoken) {
let options = {
url: availableProjects,
headers: {
'Authorization': 'Bearer ' + accesstoken,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
return request(options, async function (err, res) {
if (err) {
console.error(err + " error");
} else {
//here it gives successful output
console.log("response")
console.log(res.body);
let bodyJson = JSON.parse(res.body);
let projectName = bodyJson.projectInfo[0].project;
console.log(projectName)
await addProject(accesstoken, projectName)
return res.body;
}
});
}
async function addProject(accesstoken, projecctID) {
fbUrl = getAddFBUrl(projecctID);
let options = {
url: fbUrl,
headers: {
'Authorization': 'Bearer ' + accesstoken,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body:JSON.stringify(bodys)
}
return request.post(options, function (err, res) {
if (err) {
console.error(err + " error");
} else {
//here in response out put as permission denied 403
console.log("response")
console.log(res.body);
console.log(JSON.stringify(res));
return res.body;
}
});
}
function getAddFBUrl(projectId) {
return 'https://firebase.googleapis.com/v1beta1/' + projectId +
':addFirebase';
}
i found one similar question to this. But it didn't helped me to resolve my issue which is here
AskFirebase
From the Firebase REST reference: Method: projects.addFirebase
To call projects.addFirebase, a member must be an Editor or Owner for
the existing GCP Project. Service accounts cannot call
projects.addFirebase.
Update:
To call projects.addFirebase, a project member or service account must have the following permissions (the IAM roles of Editor and Owner contain these permissions): firebase.projects.update, resourcemanager.projects.get, serviceusage.services.enable, and serviceusage.services.get.
https://firebase.google.com/docs/projects/api/reference/rest/v1beta1/projects/addFirebase
I'm not sure if my answer will be helpful for author of this question, but this if first two things all should check when facing 403 Error with Google Cloud APIs
0) Check configuration with gcloud
1) As mentioned before the first thing is to check the role of service account. You need Editor/Owner usually.
https://cloud.google.com/iam/docs/understanding-roles
https://console.cloud.google.com/iam-admin
2) The second one is to check if API enabled for project at all.
Also when creating a key check it for correct service account.
For someone who's just get started like me, this thing maybe helpful. When I seted up database, I choose Start in locked mode instead of Start in test mode. Therefore, I can't read or write :((. For beginner, just set everything in test mode. Hope it helpful.
https://i.stack.imgur.com/nVxjk.png
Your problem means that your project is not linked with your firebase account which means you have to login with your firebase account. Than you will have the permission
type cd functions in your firebase project directory
type firebase login
login with the Gmail which is connected with your firebase account
It'll work
I'm following the official instructions on how to send push notifications to users that gives their permission.
I'm able to follow all the instructions until this code
appMap.set('finish.push.setup', function(app)) {
if (app.isPermissionGranted()) {
const intent = app.getArgument('UPDATE_INTENT');
const userID = app.getArgument('UPDATES_USER_ID');
// code to save intent and userID in your db
app.tell("Ok, I'll start alerting you");
} else {
app.tell("Ok, I won't alert you");
}
}
the app.getArgument('UPDATE_INTENT') return undefined and checking the JSON it looks like it doesn't contain the intent at all but I have only one intent configured for updates so I hardcoded it's name in the code.
I got a userID and I hardcoded it too in the code.
Then I followed the instructions to get a service account key and I saved the JSON key locally.
Then the nasty problems begins.
I installed the required packages with npm install googleapis request --save and copied the code
const google = require('googleapis');
const key = require(PATH_TO_KEY);
let jwtClient = new google.auth.JWT(
key.client_email, null, key.private_key,
['https://www.googleapis.com/auth/actions.fulfillment.conversation'],
null
);
jwtClient.authorize(function (err, tokens) {
// code to retrieve target userId and intent
let notif = {
userNotification: {
title: '',
},
target: {
userId: '',
intent: ''
}
}
request.post('https://actions.googleapis.com/v2/conversations:send', {
'auth': {
'bearer': tokens.access_token
},
'json': true,
'body': { 'customPushMessage': notif }
}, function(err,httpResponse,body) {
console.log(httpResponse.statusCode + ': ' + httpResponse.statusMessage)
});
});
I edited it setting the right path to my key and edited the notification property with fixed values (the same title configured in the action, the userID returned by dialogflow and the name of my intent).
Then I noticed that the code is missing a const request = require('request'); and the line
let jwtClient = new google.auth.JWT(
gives an error so I changed to
let jwtClient = new google.google.auth.JWT(
I added a console.log('body', body); just to get more data and I got
body { error:
{ code: 404,
message: 'App [my-project-id] was not found. The app preview may have expired.',
status: 'NOT_FOUND' } }
Am I doing something wrong or the documentation has other errors I still have to catch?
try to add locale at target object:
let notif = {
userNotification: {
title: '',
},
target: {
userId: '',
intent: '',
locale: ''
}
}
For locale follow IETF BCP-47 language code as described here.
By default Google Actions use en-US language, and I figure out you are using a differente language code, so the system reply that cannot found us version of your application.
Just getting started with Firebase phone auth. Seems pretty slick however I've hit a wall with a bug.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "invalid",
"message": "SESSION_EXPIRED"
}
],
"code": 400,
"message": "SESSION_EXPIRED"
}
}
Starting with the Captcha: (standard documentation code!)
var applicationVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
'size': 'invisible',
'callback': function(response) {
},
'expired-callback': function() {
}
});
Its rendered and the captcha works well.
Next is the sign-in bit where you are sent the auth code to your phone. Works great:
$scope.signInWithPhoneNumber = function signInWithPhoneNumber() {
var phoneNumber = "*censored*";
var appVerifier = window.recaptchaVerifier;
firebase.auth().signInWithPhoneNumber(phoneNumber, applicationVerifier)
.then(function (confirmationResult) {
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
window.confirmationResult = confirmationResult;
$scope.setConfirmationResult(confirmationResult);
alert('Result: ' + JSON.stringify(confirmationResult));
}).catch(function (error) {
// Error; SMS not sent
alert('Error: ' + error);
// ...
});
};
Finally its the authentication of the code that the user inputs from the text message. Here is when I get the error 400:
$scope.AuthenticateCode = function (code) {
var code = String(document.getElementById("auth_code").value);
var confirmationResult = $scope.getConfirmationResult();
alert(code);
confirmationResult.confirm(code).then(function (result) {
// User signed in successfully.
var user = result.user;
console.log('Signed In! ' + JSON.stringify(user));
// ...
}).catch(function (error) {
// User couldn't sign in (bad verification code?)
// ...
});
}//end of AuthenticateCode
The error is coming from the VerifyPhone method:
https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPhoneNumber?key=censored
Any help or ideas?
Many Thanks,
Kieran
Ok, there are 2 likely reasons:
The code expired. The user took too long to provide the SMS code and finish sign in.
The code was already successfully used. I think this is the likely reason. You need to get a new verificationId in that case. Get a new reCAPTCHA token via the invisible reCAPTCHA you are using.
You are most likely to forget the "Country Code" before the phone no.
That is why firebase throw error 400 which means invalid parameters
If it's an Ionic3 project, change the following lines:
Imports:
import { AngularFireAuth } from 'angularfire2/auth';
import firebase from 'firebase';
Create var:
public recaptchaVerifier: firebase.auth.RecaptchaVerifier;
on "ionViewDidLoad()"
this.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
on "your_method(phoneNumber: number)"
const appVerifier = this.recaptchaVerifier;
const phoneNumberString = "+" + phoneNumber;
this.fireAuth.auth.signInWithPhoneNumber(phoneNumberString, appVerifier)
.then(confirmationResult => {
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
let prompt = this.alertCtrl.create({
title: 'Enter the Confirmation code',
inputs: [{ name: 'confirmationCode', placeholder: 'Confirmation Code' }],
buttons: [
{
text: 'Cancel',
handler: data => { console.log('Cancel clicked'); }
},
{
text: 'Send',
handler: data => {
confirmationResult.confirm(data.confirmationCode)
.then(result => {
// Phone number confirmed
}).catch(error => {
// Invalid
console.log(error);
});
}
}
]
});
prompt.present();
})
.catch(error => {
console.error("SMS not sent", error);
});
Reference:
Firebase Phone Number Authentication
I got into a similar situation when a POST request to google API was returning Bad Request 400. When the message was logged, it said:
All requests from this device are blocked due to Unusual Activity. Please try again later
The issue was when the ReCaptcha was sensing a bot out of my development environment and it worked well when I tried later. During the rest of the development, I turned off this feature for easy work.
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