Im trying to make a login page to my firebase project, but always when i send the params to the functions its returns "Firebase is not defined . Here's my code:
<button id="login" onclick="signIn()"><Login</button>
The function signIn() only change the href to http://localhost:5000/signin/:email/:password
then i have this
const functions = require('firebase-functions');
const adm = require('firebase-admin');
const express = require('express');
const signin = require('./modules/signin');
const firebase = require("firebase");
// // Create and Deploy Your First Cloud Functions
adm.initializeApp(
functions.config().adm
);
const app = express();
app.get('/signin/:email/:password', (request, response) => {
exports.signin = signin(request.params.email, request.params.password);
});
exports.app = functions.https.onRequest(app);
and my function is only
function signin (email, password) {
firebase.auth().signInWithEmailAndPassword(email, password).then(function(user) {
// user signed in
console.log ("Usuário logado com sucesso!");
return True;
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
// alert('Wrong password.');
return false;
} else {
alert(errorCode+": "+errorMessage);
return false;
}
});
}
module.exports = signin;
im trying to use the index.js on functions folder as a type of "controller" to call functions on backend, but im having trouble to solve this simple problem.
You can't use the Firebase client SDK in Cloud Functions. Cloud Functions is considered backend code, and doesn't run on the browser. If you want to sign in the user, you have to use the SDK in your browser code, not backend code.
Related
I have a server.js file in Express and Node.js that contains the majority of my back-end code, outside of my database config file.
The file is quite long and to improve maintainability, I would like to make it modular by splitting various components into their own files that can be imported.
I have attempted to move a database endpoint as a starting point into its own file called auth.js, located in the routes folder. The file is set up as follows:
const express = require('express');
const router = express.Router();
const db = require('../config/db');
const crypto = require("crypto"); // set up crypto middleware for hashing password and checking password hashes
const salt = crypto.randomBytes(256).toString("hex"); // create a hash salt/pepper
const iterations = 1000; // number of iterations to jumble the hash
const hashSize = 64; //set up char length of hash
const hashAlgorithm = "sha256"; // which hashing algorithm will be used
//This function returns a hash of the password, combined with the pepper and the salt.
function PasswordHash(password, salt) {
//PEPPER MUST BE MOVED TO ENV FILE WHEN READY
const pepper = "ec3fd71d14f7cab570fc94df34e60e4d8c80cdff4d1dde66c74b10ae576b88239315295adabaced63b05104bbf8d2f2f92a24aeebe8444861ba1b7efc73dafdeda6fe2bf6e7288f959832d5db953a7eab0b37ef8ad126f94616b0c1e7b3b0ce7418dff91afaa78401dacce6aee72649840e26a01d75bfac69acf8d0dd50aaddebb9397150bb0f88795cde94ea3d03fec2992fc3b5c3c7bbd8de3f8f7d693cdcca879d9aefd6e02d4457217928091a731c08f83f9927f9b19ca34ab589dd02ecc40e336e067a1f2e072ec2b3a93617ded73028ed5bc5d55f011ba5a53099312f06d649fa06fdbf49e81c8f9a81f113f95cd416d230c2cb6056189c77f889dc83d";
return crypto.pbkdf2Sync (
password,
salt + pepper,
iterations,
hashSize,
hashAlgorithm
).toString("hex");
};
// login route
router.post('/signin', (req, res) => {
const { email, password } = req.body;
// Check all emails against input
db.query(selectEmail, [email], (err, rows) => {
if (err) throw err;
// If email exists
if (rows.length > 0) {
// If password with salt and compares to database
if (PasswordHash(password, rows[0].salt) == rows[0].password) {
// Create session
req.session.firstName = rows[0].first_name;
req.session.lastName = rows[0].last_name;
req.session.username = rows[0].user_name;
req.session.ProfilePicture = rows[0].profile_picture;
console.log('Session created:', req.session); // Print session
res.send('Login successful');
}
// If password is incorrect
else {
res.send('Email or password are incorrect');
}
}
// If email does not exist
else {
res.send('Email or password are incorrect');
};
});
});
module.exports = router;
This is then used in the main server.js file by requiring the auth.js file and using it with the route '/signin':
const authRoutes = require('./routes/auth');
app.use('/signin', authRoutes);
Finally, I make a request on my React front-end application to the /signin route.
const validateRow = () => {
// Validate login
axios.post('http://localhost:8080/signin', {
email: emailInput,
password: passwordInput
})
.then((res) => {
setMessage(res.data);
//If validation passed
if (res.data === 'Login successful') {
navigate('/directory')
};
});
};
To add some context this is for a login form and validates login data inputted into the form against rows found in the database. This worked as intended until I moved the endpoint into a separate file I now receive:
AxiosError {message: 'Request failed with status code 404', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
on my front end. I would like to know how to resolve this issue.
The issue is that app.use('/signin', authRoutes) makes an endpoint be "/signin/signin" not just "/signin" which you are trying to request. The simplest solution would be to change link you pass in axios.post function to "http://localhost:8080/signin/signin".
Try using relative path as suggested in this (possible duplicate):
I don't understand why my axios post request isn't working - 404 not found
You need to listen to the port 8080
const app = express()
const port = 8080
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
I have a simple React web app created from create-react-app.
I also have an existing user pool (set up by a third party) on Amazon Cognito. I have been given a username and password for authentication. Once authenticated, Cognito provides a JWT token.
What I want to achieve is to authenticate the user and get a JWT access_token within the componentDidMount method of the App component; then use the token to call other APIs to retrieve some data and then show the data on the App component.
The following info is known:
region
USER_POOL_ID
APP_CLIENT_ID
USER_ACCOUNT
USER_PASSWORD
AWS provides the authenticate_and_get_token function for Python developers. Is there an equivalent for JavaScript and React developers? Any sample code is appreciated.
Don't know about the authenticate_and_get_token you mentioned, couln't find this function in Boto3 docs.
But I do know different function to retrieve a token called adminInitiateAuth. This is function available for JS.
you can implement this using Lambda, like this:
const AWS = require('aws-sdk');
const USER_POOL_ID = "us-east-1_*******";
const APP_CLIENT_ID = "***********";
const USER_ACCOUNT = "***********";
const USER_PASSWORD = "***********";
const cognitoClient = new AWS.CognitoIdentityServiceProvider({
apiVersion: "2016-04-19",
region: 'us-east-1'
});
exports.handler = async (event) => {
try {
const userData = await userSignIn(USER_ACCOUNT, USER_PASSWORD);
return userData // refer to userData.AuthenticationResult.IdToken;
} catch(e){
throw e;
}
};
const userSignIn = async (username, password) => {
try {
var params = {
AuthFlow: 'ADMIN_NO_SRP_AUTH',
ClientId: APP_CLIENT_ID ,
UserPoolId: USER_POOL_ID,
AuthParameters: {
USERNAME: username,
PASSWORD: password
}
};
return await cognitoClient.adminInitiateAuth(params).promise();
} catch (err) {
return err.message ? err : {message : err};
}
};
Please make sure you have the specific permission to invoke this method, like "Action": "cognito-idp:AdminInitiateAuth", in the lambda permissions, or in IAM role.
I'm frustrated and confused. I'm trying to deploy my cloud functions but whenever I do they're not updating properly and despite firebase saying that they were updated successfully, keep serving the old function. Here's my index.js:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
//Cloud functions for user interaction
const charge = require('./func/charge');
const addProduct = require('./func/addProduct');
const removeProduct = require('./func/removeProduct');
const updateTracking = require('./func/updateTracking');
admin.initializeApp(functions.config().firebase);
exports.charge = functions.https.onRequest(charge);
exports.updateTracking = functions.https.onRequest(addProduct);
exports.addProduct = functions.https.onRequest(removeProduct);
exports.removeProduct = functions.https.onRequest(updateTracking)
And here's my addProduct function with everything stripped away. This still doesn't update.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
const request = require('request');
const send = require('../send.js');
const cors = require('cors')({origin: '*'});
function addProduct(req, res) {
console.log('THIS NEVER PRINTS')
send(res, 500, {
error: `FAILURE`
})
}
const appAddProduct = express();
appAddProduct.use(cors);
appAddProduct.post('/', (req, res) => {
// Catch any unexpected errors to prevent crashing
try {
addProduct(req, res);
} catch(e) {
console.log(e);
send(res, 500, {
error: `The server received an unexpected error. Please try again and contact the site admin if the error persists.`,
});
}
});
module.exports = appAddProduct
This is still serving up a success message & status code 200 from an older function with a logic error in it when this should just be serving up a 500 error every time. Something is clearly wrong with the way I've split this into multiple files as that is where the trouble started but I'm not sure where I've gone wrong. Help would be much appreciated.
Your exported function names don't match the names of the imported files:
exports.charge = functions.https.onRequest(charge);
exports.updateTracking = functions.https.onRequest(addProduct);
exports.addProduct = functions.https.onRequest(removeProduct);
exports.removeProduct = functions.https.onRequest(updateTracking)
I see that three of the four functions are not paired with the same-named imports. The only one that matches is charge. I suspect you didn't intend to do this.
How can I run HTTP functions and Realtime Database functions simultaneously
I see in the documentation here : Run functions locally how to run HTTP functions by the following command : firebase serve and for the Realtime Database functions : firebase functions:shell but it doesn't work for me.
And also when I deployed my functions with command firebase deploy --only functions it only deploy my HTTP function .
What is wrong with my approach ?
structure:
/functions
|--index.js
|--saveDetectedBeacons.js
|--generatePresence.js
|--package.json
index.js:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
const saveDetectedBeaconsFunc = require('./saveDetectedBeacons');
const generatePresenceFunc = require('./generatePresence');
const serviceAccount = require("./serviceAccountKey");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://exampleDb.firebase.com"
});
const db = admin.database();
exports.saveDetectedBeaconsApi = functions.https.onRequest((request, response) => {
saveDetectedBeaconsFunc.handler(request,response,db)
});
exports.generatePresenceApi = functions.database.ref('/reports').onCreate((snapshot, context) => {
generatePresenceFunc.handler(snapshot, context, db)
});
saveDetectedBeacons.js:
exports.handler = function (request, response, db) {
// do something
};
generatePresence.js
exports.handler = function (snapshot, context, db) {
// do something
};
I have some trouble with Cloud function and firestore rules.
I would like use cloud function with limited privilèges on Firestore and give
only has access as defined in the Security Rules
It's working without problem on RTDB but not on Firestore.
I have try with this rules
service cloud.firestore {
match /databases/{database}/documents {
match /init/{ID=**} {
allow read, write: if true;
}
match /test/{ID=**} {
allow read, write: if false;
}
}
}
And this
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const FieldValue = require('firebase-admin').firestore.FieldValue;
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://******.firebaseio.com',
databaseAuthVariableOverride: {
uid: 'my-worker',
},
});
const db = admin.firestore();
exports.onTestRights = functions.firestore
.document('init/{initID}')
.onCreate((event) => {
const initID = event.params.initID;
return db.collection('test').doc(initID).set({'random key': 'random value'}).then(()=>{
console.log('working');
return;
}).catch((err) =>{
console.log('error: ', err);
return;
});
});
But it's still writing so whereas it should be "permission denied"
Anyone know if it's normal(or not yet implanted) on firestore or I have misunderstood something ?
Edit:
Of course my final goal is not with this rules, but only give write/read access on some documents/collections using (allow read, write: if request.auth.uid == 'my-worker';)
Edit2:
I would like use the security rules for checking like a transaction if no change during process using this model
As you've noticed databaseAuthVariableOverride only works for the Realtime Database. There is nothing right now that allows you to do the same for Firestore in the Admin SDK.
One workaround you could use if you want to limit the access rights on your server code is to use the Client JS SDK rather than Firebase Admin and sign the user-in using a custom token. Here is a sample code to do this:
// Configure Firebase Client SDK.
const firebase = require('firebase/app');
require('firebase/auth');
require('firebase/firestore');
firebase.initializeApp({
// ... Initialization settings for web apps. You get this from your Firebase console > Add Firebase to your web app
});
// Configure Firebase Admin SDK.
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
// Create Custom Auth token for 'my-worker'.
const firebaseReady = admin.auth().createCustomToken('my-worker').then(token => {
// Sign in the Client SDK as 'my-worker'
return firebase.auth().signInWithCustomToken(token).then(user => {
console.log('User now signed-in! uid:', user.uid);
return firebase.firestore();
});
});
// Now firebaseReady gives you a Promise that completes with a authorized firestore instance. Use it like this:
exports.onTestRights = functions.firestore
.document('init/{initID}')
.onCreate(event => {
const initID = event.params.initID;
return firebaseReady.then(db => db.collection('test').doc(initID).set({'random key': 'random value'}).then(() => {
console.log('working');
return;
}).catch((err) =>{
console.log('error: ', err);
return;
});
);
});