Cloud Functions with Firebase: signInWithEmailAndPassword is not a function - node.js

I'm beginning writing code with Cloud Functions with Firebase.
Of the functions below, testCreateUserAccount succeeds.
testLogin fails with a Type Error at runtime, stating "signInWithEmailAndPassword is not a function"
From what I have seen in the documentation, createUser is under the same class as signInWithEmailAndPassword, so its not clear to me why attempting to call signInWithEmailAndPassword would fail. Any ideas? Thanks!
"use strict";
var functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.testCreateUserAccount = functions.https.onRequest ((req, res) => {
var email = "joe#example.com";
var password = "joejoe";
admin.auth().createUser({
email: email,
password: password,
disabled: false
});
} );
exports.testLogin = functions.https.onRequest ((req, res) => {
var email = "joe#example.com";
var password = "joejoe";
admin.auth().signInWithEmailAndPassword(email, password);
} );

You used admin.auth().signInWithEmailAndPassword(email, password) on server side, you must use it on client side.

Now you could use the identitytoolkit's rest endpoint:
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
Here you have the documentation:
https://firebase.google.com/docs/reference/rest/auth/

You can use Identity toolkit REST API like this then response with idToken. IdToken can be use to verify an account using admin.auth().verifyIdToken(idToken) in Cloud Function.
https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=YOUR_PROJECT_API_KEY_THAT_ALLOWS_IDENTITY_TOOLKIT_SERVICE&email=test#gmail.com&password=samplepass&returnSecureToken=true

Related

Firebase Functions : SignatureDoesNotMatch

I had an error in deploying Firebase functions after I changed my laptop and also transferred ownership of my Firebase account to another for a 3-month free Blaze plan. While deploying any functions, I am getting this error. All Firebase functions are successfully running locally.
Error code
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message> The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
<StringToSign GET 1670330017 /uploads-abc.zip</StringToSign></Error>
index.js
`
const functions = require("firebase-functions");
const admin = require("firebase-admin");
var handlebars = require("handlebars");
var fs = require("fs");
const nodemailer = require("nodemailer");
var serviceAccount = require("../service_account.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: "gs://xyz.com",
databaseURL: "https://xyz",
});
transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: "username",
pass: "password",
},
});
readHTMLFile = function (path, callback) {
fs.readFile(path, { encoding: "utf-8" }, function (err, html) {
if (err) {
callback(err);
throw err;
} else {
callback(null, html);
}
});
};
exports.sendWelcomeMail = functions.https.onCall(async (data, context) => {
// Grab the text parameter.
const email = data.email;
const name = data.name;
readHTMLFile(`./welcome_page.html`, function (err, html) {
var template = handlebars.compile(html);
var replacements = {
name: name,
};
var htmlToSend = template(replacements);
var mailOptions = {
from: "from-mail",
to: email,
subject: "Welcome to boom boom",
html: htmlToSend,
};
transporter.sendMail(mailOptions, (erro, info) => {
if (erro) {
console.log(erro.toString());
return erro.toString();
}
console.log("Sended");
return "Sended";
});
});
});
`
I had tried different service account private keys which we can get from firebase project settings, with that I had tried deploying functions from different account ex. owners account, other account with service admin access.
Please check that SHA keys (SHA-1 and SHA-256) in your Firebase project (Project Settings -> General -> Your Apps -> Select your android app -> SHA certificate fingerprints) are same as in Google Play Console (Setup -> App integrity -> App Signings -> App Signing Key Certificate).
Specially if you are using Google play signing to release your app.
try in your terminal :
login with your firebase account firebase login:ci you will be redirected to your browser, you have to login
come back to the terminal (now you are logged in) and type firebase projects:list to list all the projects that you can access with your logged in firebase account
choose the project you want to deploy your function to : firebase use
NB: you are assumed to have npm and firebase-tools already installed in your terminal

Gmail API service account request- Precondition check failed

I'm trying to work with the google API's for the first time, and when I attempt to make a request to the gmail API I'm getting a "precondition check failed" error. I am using a service account authorization, not Oauth2 user consent. Things I've tried:
Authorized "domain wide delegation" for the service account.
Ensured the APP is trusted in the G suite account.
Ensured service account role is "owner"
Enabled domain wide delegation for the client ID of the service account in the g suite admin panel.
This is an adapted sample from the Node client library, but the sample did not use service account auth so I wasn't able to use the sample directly.
const path = require('path');
const {google} = require('googleapis');
const gmail = google.gmail('v1');
async function runSample() {
// Obtain user credentials to use for the request
const auth = new google.auth.GoogleAuth({
keyFile: path.resolve(__dirname, 'google-key.json'),
scopes: ['https://www.googleapis.com/auth/gmail.readonly'],
});
google.options({auth});
const res = await gmail.users.messages.list({userId: 'me'}); // have tried with my gsuite email address as well
console.log(res.data);
return res.data;
}
if (module === require.main) {
runSample().catch(console.error);
}
module.exports = runSample;
Returning error with message: Error: Precondition check failed.
After searching the dark web for eternity, I found a link to a github issue that described how to authenticate as a service using JWT auth.
This is a working version of what I was trying to accomplish:
const path = require('path');
const {google} = require('googleapis');
async getMessageList(userId, qty) {
const JWT = google.auth.JWT;
const authClient = new JWT({
keyFile: path.resolve(__dirname, 'google-key.json'),
scopes: ['https://www.googleapis.com/auth/gmail.readonly'],
subject: 'admin#example.com' // google admin email address to impersonate
});
await authClient.authorize(); // once authorized, can do whatever you want
const gmail = google.gmail({
auth: authClient,
version: 'v1'
});
const response = await gmail.users.messages.list({
includeSpamTrash: false,
maxResults: qty,
q: "",
userId: userId
});
// the data object includes a "messages" array of message data
return response.data;
}

app.auth(...).signInWithCredential is not a function firebase error

I'm trying to add google login to my node js firebase app. I'm getting the following error:
app.auth(...).signInWithCredential is not a function
Here's the code on the server
var credential = firebase.auth.GoogleAuthProvider.credential(id_token);
return app.auth().signInWithCredential(credential);
On the client
// We need to register an Observer on Firebase Auth to make sure auth is initialized.
var unsubscribe = app.auth().onAuthStateChanged((firebaseUser) => {
unsubscribe();
// Check if we are already signed-in Firebase with the correct user.
// Build Firebase credential with the Google ID token.
var credential = firebase.auth.GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token);
// Sign in with credential from the Google user.
firebase.auth().signInWithCredential(credential).catch( (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;
console.dir(errorMessage);
}).then( (success) => {
console.dir(success);
var id_token = googleUser.getAuthResponse().id_token;
axios.post('/auth/google-login', {
id_token: id_token
}).then(response => {
var result = response.data;
if (result.status === "ok") {
this.setState({complete: true});
} else if (result.error) {
this.setState({error: result.error});
}
}).catch(error => {
console.dir(error);
this.setState({error: "error"});
});
});
});
What I'm I doing wrong?
At the top of the nodejs file, I have
var app = require('./base');
where base :
var serviceAccount = require("./service-account-file.json");
const app = fadmin.initializeApp({
credential: fadmin.credential.cert(serviceAccount),
databaseURL: "https://test.firebaseio.com"
});
module.exports = app;
Hi there are hints that the problem starts with node version 6.21. that
app.auth().signInWithCredential(credential)
Don't work
It works in v6.2.0.
Try signInWithEmailAndPassword
Use latest version of node
The function signInWithCredential is part of the Firebase JavaScript SDK
The Firebase JavaScript SDK implements the client-side libraries used by applications using Firebase services.
The Firebase Admin SDK is intended to run on a server or other privileged environment. The Admin SDK does not include sign-in functions.

Cloud Function to Authenticate a User

I am attempting to authenticate a user to access various scopes in the user Gsuite. I can run the code locally but I cannot seem to get it accepted as a cloud function.
I have tried deploying with firebase and with gcloud. I have checked my eslint settings.
This code is coming from https://github.com/googleapis/google-api-nodejs-client/blob/master/README.md#oauth2-client
'use strict';
const fs = require('fs');
const path = require('path');
const http = require('http');
const url = require('url');
const opn = require('open');
const destroyer = require('server-destroy');
const {google} = require('googleapis');
/**
* To use OAuth2 authentication, we need access to a a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI. To get these credentials for your application, visit https://console.cloud.google.com/apis/credentials.
*/
const keyPath = path.join(__dirname, 'credentials.json');
let keys = {redirect_uris: ['']};
if (fs.existsSync(keyPath)) {
keys = require(keyPath).web;
}
/**
* Create a new OAuth2 client with the configured keys.
*/
const oauth2Client = new google.auth.OAuth2(
keys.client_id,
keys.client_secret,
`http://localhost:3000/oauth2callback`
);
/**
* This is one of the many ways you can configure googleapis to use authentication credentials. In this method, we're setting a global reference for all APIs. Any other API you use here, like google.drive('v3'), will now use this auth client. You can also override the auth client at the service and method call levels.
*/
google.options({auth: oauth2Client});
const scopes = ['https://www.googleapis.com/auth/documents'];
/**
* Open an http server to accept the oauth callback. In this simple example, the only request to our webserver is to /callback?code=<code>
*/
async function authenticate(){
// grab the url that will be used for authorization
const authorizeUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes
});
const server = http.createServer(async (req, res) => {
try {
if (req.url.indexOf('/oauth2callback') > -1) {
const qs = new url.URL(req.url, 'http://localhost:3000').searchParams;
res.end('Authentication successful! Please return to the console.');
server.destroy();
const {tokens} = await oauth2Client.getToken(qs.get('code'));
oauth2Client.credentials = tokens; // eslint-disable-line require-atomic-updates
resolve(oauth2Client);
}
} catch (e) {
reject(e);
}
})
.listen(3000, () => {
// open the browser to the authorize url to start the workflow
opn(authorizeUrl, {wait: false}).then(cp => cp.unref())
.catch(
error => {
console.log(error);
});
});
destroyer(server)
.then(client => runSample(client)).catch(
error => {
console.log(error);
});
};
module.exports.authenticate=authenticate;
async function runSample(client) {
// retrieve user profile
console.log(client);
const docs = google.docs({
version: 'v1',
auth: client
});
const createResponse = await docs.documents.create({
requestBody: {
title: 'Your new document!',
},
});
}
I expect it to load as a cloud function to firebase or gcloud.
However:
Firebase returns "Deploy complete" but it never shows in the functions.
gcloud returns "SyntaxError: Unexpected token function" with the word function indicated in "async function authenticate(){"
I'm new to node.js and may be missing something really obvious to others.
You will never get User Credentials (Client ID/Client Secret) to work
in Cloud Functions (meaning authenticate and create credentials).
OAuth requires a web browser and a human. Neither one exists in Cloud
Functions. Use a Service Account instead. – John Hanley

Firebase authentication (is not a function, is not a constructor)

I don't know what is wrong. I'm using Node.js and trying to log in using email/password and Google authentication. I have enabled all of them in Firebase console.
npm Firebase version - 3.1.0
part of code:
var firebase = require('firebase');
var config = {
apiKey: "AIzaSyAH27JhfgCQfGmoGTdv_VaGIaX4P-qAs_A",
authDomain: "pgs-intern.firebaseapp.com",
databaseURL: "https://pgs-intern.firebaseio.com",
storageBucket: "pgs-intern.appspot.com",
};
firebase.initializeApp(config);
app.post('/login', function(req, res) {
var auth = firebase.auth();
firebase.auth().signInWithEmailAndPassword(req.body.login, req.body.password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
}
Error: firebase.auth(...).signInWithLoginAndPassword is not a function
or
Error: firebase.auth(...).GoogleAuthProviders is not a constructor when I write
firebase.auth().signInWithPopup(provider).then(function(result) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.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;
// ...
});
I just did exactly what is in documentation.
Your first error probably comes from a typo somewhere.
firebase.auth(...).signInWithLoginAndPassword is not a function
Notice it says signInWithLoginAndPassword, the function is called signInWithEmailAndPassword. In the posted code it's used correctly, so it's probably somewhere else.
firebase.auth(...).GoogleAuthProviders is not a constructor
You have not posted the code where you use this, but I assume this error happens when you create your provider variable, that you use in firebase.auth().signInWithPopup(provider)
That line should be var provider = new firebase.auth.GoogleAuthProvider();
Based on the error message, I think you might be doing new firebase.auth().GoogleAuthProvider(); Omit the brackets after auth, if that's the case.
Do not call GoogleAuthProvider via an Auth() function.
According to the documentation you have to create an instance of GoogleAuthProvider.
let provider = new firebase.auth.GoogleAuthProvider()
Please check the following link https://firebase.google.com/docs/auth/web/google-signin
There is no way to sign your node.js app into firebase with email+password or one of the social providers.
Server-side processes instead sign into Firebase using so-called service accounts. The crucial difference is in the way you initialize the app:
var admin = require('firebase-admin');
admin.initializeApp({
serviceAccount: "path/to/serviceAccountCredentials.json",
databaseURL: "https://databaseName.firebaseio.com"
});
See this page of the Firebase documentation for details on setting up a server-side process.

Resources