Firebase Authentication via Server Side to access routes - javascript

I am using sessionStorage and also firebase authentication for email and password.
In my server.js I am wondering how can I make it so that if a user is not logged in they cannot access a route, or rather be redirected to the login route instead.
The firebase sdk I am using is only usable via the client side. Is there any documentation to help that I have been unable to find.
Please let me know if I need to clarify my question more and I will do my best to do so.
Here is my server.js:
const express = require('express');
const admin = require('firebase-admin');
const bcrypt = require('bcrypt');
const path = require('path');
let serviceAccount = require("./1234.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
let staticPath = path.join(__dirname,"public");
const app = express();
app.use(express.static(staticPath));
app.use(express.json());
app.get('/login', (req,res) => {
res.sendFile(path.join(staticPath, "form.html"));
})
app.get('/seller', (req,res) => {
// if(!user) res.redirect('/login');
res.sendFile(path.join(staticPath, "seller.html"));
})
Edit:
So far the only thing that helps me with this is by creating a seller.js
and inserting this code here, but I am unsure of if this method is safe or if there is a way to hide this from being manipulated:
body = document.getElementsByTagName('BODY')[0];
user = JSON.parse(sessionStorage.user);
if(user && user.seller){
console.log('Allow Access')
} else{
console.log('Deny')
body.innerHTML = `
<div class="sticky" id="nav"></div>
<div style="padding:300px">
<center>You do not have permission to view this page.</center>
</div>
<div id="footer"></div>
`;
}

You can use the firebase-admin package to verify the token on the server. If the verification passes, you can continue with route logic. To make things simple, you could wire up a middleware in Express that verifies the token, rather than repeating the calls for authenticated routes.
Relevant documentation: https://firebase.google.com/docs/auth/admin/verify-id-tokens#web
Also, you should not rely on client-side scripting to verify a user's authentication status if you're trying to restrict resources on a server. It would be trivial for someone to find the endpoints being used, and, assuming there's no logic on the server to verify the user, they could potentially retrieve sensitive information.

Related

How can I setup an OpenID Connect authentication with Node Js?

here is the thing. I have my app that has separated back-end and front-end into two different project (back-end with Node-JS, and front-end with Vue-JS). I got a home page with a button that should redirect the user to the authentication server to log in.
So i made an "on-click" function in my homePage.vue that will consume a function from my api.
I've read a lot of documentation and seen some examples. But to be honest, during those past weeks, even if I tried, I still do understand nothing about how authentication works.
You can see below the js file i wrote inspired by examples that i found:
auth.js
const express = require('express');
const { auth } = require('express-openid-connect');
const app = express();
app.use(
auth({
issuerBaseURL: 'myDomainUrl',
baseURL: 'http://localhost:8080',
clientID: 'myClient_ID',
secret: 'aaaaaaaaaaaaaaaaaaaa',
idpLogout: true,
authRequired: false,
})
);
module.exports = app;
There is also the route with the function that I try to implement:
auth.route.js
module.exports = app => {
var router = require("express").Router();
router.get('', location.replace('myDomainUrl'));
app.use('/api/login', router);
};
I don't know if it's important but my back-end runs on the port 4000 and my front-end runs on the port 8080.
If someone can explain me how I can do to make my authentication work and what I have to change, it would be great.
Thanks you in advance, I hope I was clear enough about my problem. If not, do not hesitate to ask me what was not clear.

How to pass id of object to another page?

I have full stack application which i deployed on netlify, my frontend structure (vanilaJS) is following:
client
-index.html
-training.html
-scripts
-style
My backend is in Express and successfuly deployed to Heroku. I have the following rutes:
const express = require('express')
const app = express()
const trainingRoute = require('./routes/training')
app.use('/training', trainingRoute)
In the index.html on frontend i have card:
<div class="trening-plan-container">
<div class="plan-btn">
<button>Pogledaj</button>
</div>
</div>
452153221489 is id of item in database. When i click on link, i get my url:
https://example.netlify.app/training/452153221489
and i get 404 status, not found.
How can i make request to my backend route /training/452153221489 which i have defined in
app.use('/training', trainingRoute) :
const express = require('express')
const router = express.Router()
const {
getTrainingPlan,
} = require('../controllers/trainingPlan')
router.route('/:id').get(getTrainingPlan)
module.exports = router
When i use fetch, everything works, because i specify full url
https://trening-bek.herokuapp.com/training/452153221489
After days of research i have found proxy might be the solution but it doesn't work.
I could use Pogledaj then retreive id and make fetch api call but I'm not sure that's the way it should be done.
Is it bad practice to seperate frontend and backend on two servers?

Is it normal that I am able to invoke firebase cloud functions from any kind of frontend app?

I am using axios to call the firebase cloud functions I have created with express/firebase. I realized even without using and without importing the firebase and without initializeApp(firebaseConfig) in my frontend, I was able to call my cloud functions with the axios with the following way:
axios.get('https://us-central1...')
How I create cloud functions:
index.js
module.exports ={
...require('./controllers/foo')
}
foo.js
const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
const app = express();
//Middleware
app.use(express.json());
app.use(cors({ origin: true}));
app.get('/', async (req, res) => {
// Function goes in here
});
app.post('/', async (req, res) => {
// Function goes in here
});
app.put('/:id', async (req, res) => {
// Function goes in here
});
app.delete('/:id', async (req, res) => {
// Function goes in here
});
exports.foo = functions.https.onRequest(app);
Is this a normal behavior or is it due to way of working of express (cors as middleware) or axios somehow? Or do I just have to add auth and firestore rules into my database? Whatever the reason is then what is the meaning of the firebaseConfig information that firebase provides for us?
PS: Just to play around I have tried to add firestore rules. I have added the following rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Even though in rules playground I was not able to retrieve anything, from my application I still got the query I wanted and I don't know why.
Yes that is absolutely normal. The HTTP Functions are made so you can integrate you Firebase Project with any (absolutely any) other language or platform by using HTTP requests as the trigger name shows. As you already do, you can even implement express apps behind those requests.
With those you gave full power and responsebility what goes trough them and with that comes also the need for you to know who is calling your HTTP requests. if you want to secure them you can use the link from the comment and check how to make Authorized HTTP Ednpoinds.
If you want to call those just from your App Frontend I would recommend to use Callable Firebse Functions because those will work only from your app and also provide the data of the user who called them in the context of your cloud function triggered.

Node.js with firebase does not save info in the Session

I am trying to use session in my app, to keep track on user log-in and more.
But...
When I tried using the simplest way, I kept getting the error :
Warning: connect.session() MemoryStore is not designed for a production environment, as it will leak memory, and will not scale past a single process.
There for, after much searching, I added the firebase-session functionality,
but now, even though I get no error, nothing is saved in the session.
This is my code:
const functions = require('firebase-functions');
const express = require('express');
const session = require('express-session');
const FirebaseStore = require('connect-session-firebase')(session);
const firebase = require('firebase-admin');
const ref = firebase.initializeApp(
functions.config().firebase
);
const app = express();
app.use(session({
store: new FirebaseStore({
database: ref.database()
}),
secret: 'asdfasgbrwewet53hnhwetynsy',
resave: true,
saveUninitialized: true
}));
app.get('/', function(req, res, next) {
console.log(req.session);
req.session.username='rakafa';
res.send('Returning with some text');
});
app.get('/bar', function(req, res, next) {
console.log(req.session);
var someAttribute = req.session.username;
res.send(`This will print the attribute I set earlier: ${someAttribute}`);
});
exports.app = functions.https.onRequest(app);
This is what I did so far:
My original example taht I used to start using session: session-express example
I took the firebase part from npm: npm firebase-session
Tried to use radis-store as a solution, didn't word: using radis-store solution
Using session-store, gave me the same worning as using nothing.. npm session-store
This question gave me the idea of using firebase-session database sessions explanations
I saw this an example with cookies, but didn't understand, and didn't find another example cookie session
Just another word, I only just started learning Node.js, so please try using simple examples, so I would understand ;)
And please forgive my starte's mistakes
Please, HELP....
=== edit ===
According to orxelm's answer, I changed my ref to this:
const ref = firebase.initializeApp({
//admin.credential.cert(serviceAccount)
credential: firebase.credential.applicationDefault(),
databaseURL: "https://*****.firebaseio.com/"
});
But still, when I run the app, there is nothing in the session once I refresh the page.
sessions in the server
^^
I can see that the app created a lot of sessions in the server.
but none of them have the information I added on the app,
and since I use only one browser, there should only one session, am I wrong?
I had this problem, when I was using firebase hosting and functions, but can be solved by simply setting name:"__session" in the session.
app.use(session({
name:"__session,
...
after adding this, saving values in the session like req.session.username='rakafa' worked fine.
Where is you firebase config?
Maybe try to initialize the firebase admin this way:
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://<DATABASE_NAME>.firebaseio.com'
});

Universal username/password authentication in express.js or react.js

Setting up user authentication can be easily achieved in apache by setting up .htaccess and .htpasswd However I am developing an new web application and I am using express.js or react.js to create a web server. I searched user authentication online but they are long projects for email style logins like here. All I need is a single universal username and password. When a user browse to my website a pop appear for the username and password. (Same like .htaccess style)
As per my understandings you need http server authentication in nodejs.
I know one npm module. link
And it's pretty easy to setup also.
Basic example
// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
realm: "Simon Area.",
file: __dirname + "/../data/users.htpasswd"
});
// Creating new HTTP server.
http.createServer(basic, (req, res) => {
res.end(`Welcome to private area - ${req.user}!`);
}).listen(1337);
If anyone is interested to do in ES2016 then follow the following code. Set the babel etc to make it work.
import express from 'express';
import auth from 'http-auth';
// Configure basic auth
const basic = auth.basic({
realm: 'SUPER SECRET STUFF'
}, (username, password, callback) => {
callback(username == 'admin' && password == 'password');
});
// Set up express app
const app = express();
// Create middleware that can be used to protect routes with basic auth
const authMiddleware = auth.connect(basic);
// Protected route
app.get('/', authMiddleware, (request, response) => {
response.send('you made it!');
});
app.listen(3000);

Categories