Express backend with Firebase auth and my own database to persist users - node.js

I'm creating a system where the client in React will implement Firebase authentication, so Firebase will signIn users, but I have a backend server with Express and I need those users in my own DB (postgresql). I can use firebase-admin in the backend to verify the token sent from the client on each request, and from this token, extract user data, as well as its uid. So I could create a user in my own database with these information.
The problem is that since I'm not handling user signup in my own server, I would have to add a verification in the authentication middleware. Each time the user makes a request to the server, the backend verifies the token (with firebase-admin) and checks if the user already exists in my own database, because if it doensn't, then create this user.
I wanted to see if there is another way to handle this, since every request is not only going to verify a token but also query the database looking for the user.

Verifying the ID token in the backend code is pretty much how all Firebase backend services handle it too. They receive the ID token, request the public key from the project, decode the token, and then validate that the user is authorized for the action they're performing.
You seem to want to create a record for the user in some shared database however, which I'd typically recommend against as it affects scalability. The only thing most Firebase backend services cache is the project keys (as those require an expensive HTTP lookup) and recent encoded/decoded token pairs. But there are caches on each server separately, so it's quite different from having shared state in a database as you seem to want.

Related

How to authenticate user and send authenticated requests from client to server side in Firebase realtime database?

I have a client side React application which currently gets access of the current authenticated user through this:
const unsubscribe = onAuthStateChanged(auth, (user) => {
setCurrentUser(user);
});
Also we have realtime database rules in certain parts like
request.auth != null
Now, I'm planning to shift the firebase part to a NodeJS + express server.
For this I have installed the firebase SDK in my server. But is it safe to use the normal authentication functions from firebase SDK?
In client side app, only one user object could exist at a particular time. Whereas, in the server side, there could be several requests for authentication at the same time.
Also, even if I do the authentication, how am I going to send authenticated requests to perform CRUD operations on my realtime and firestore databases?
Note: I've heard about the firebase-admin SDK, but have also learnt that it's immensely powerful. That's why I want to avoid using it. If I have to use it, what is the right way to do so?
The recommended approach is explained here in the Authentication doc.
And yes you need to use the Admin SDK on your Node.js backend server.
Basically the mechanism is the following one:
You keep the user authentication in your React app, in other word you call the Firebase Authentication service to sign in the user (with the JavaScript SDK from your web app). Firebase creates an ID token that uniquely identifies the user. See this section.
Then when the app interacts with your Node.js backend server you can send that ID token (a JWT) to your backend and validate it using the Firebase Admin SDK. The verifyIdToken() method is used to verify an ID token, as explained in this section. The method returns the decoded ID token from which you get the user's uid.
With the user's uid you can query your Realtime and Firestore databases for the data corresponding to the user (again with the Admin SDK).
IMPORTANT: Note that the Admin SDK totally bypasses security rules. So it's up to you, in your Node.js code, to manage the access to the data corresponding to the user.

Login functionality from external API in React with Node.js

I’m having trouble figuring out how to get Node.js backend tokens into React.js frontend local storage. To login a user will use their credentials though an external websites API using the Oauth2 flow, this will be the only way to login into the application.
Currently, the user clicks a button which opens a new window in the authorization URL where the user will grant privilege. Once granted, the user is redirected to the backend endpoint which goes through passport.js and gets the required access and refresh tokens sent from the external API. This is then stored in a session on the backend database. What I want, instead, is to not store a session on a database but instead implement JWT and store the user’s data in local storage. With the current flow, its just not possible to do this and I haven’t found the right documentation to work it out.
There are many websites that implement it the exact way I want but tracking down the way they do it has appeared to be a challenge in on itself.
So instead of using passport.js, which was causing a plethora of issues, I decided to implement the Oauth2 flow myself. Instead of doing ALL the work in the backend, I broke the flow into different parts.
Originally, I sent the user to the backend where they would recieve an authorization token there. This turned out to be troublesome, instead, request an authorization code on the front end. For example, send the user to the Auth path and redirect the user back the the front end once privileges have been granted. Wait at the frontend callback for a code, once obtained, send a post request to the backend with that code and any other data in the body.
When obtained at the backend, trade that code for the access token and respond to the post requst with the neccassary token and any other data that needs to be sent back e.g. profile name, picture, date of birth. You can the implementn the JWT flow and no database is required to store any session or tokens, all can be stored client side securely.

How can I secure my Node.js backend api data?

I may be a little confused about how backend servers work. Let's say I have a frontend React app with a login. The login information is stored in a database (i.e. MSSQL, MySQL, MongoDB) and I have a Node backend with routes for my app to fetch that information when a user is logging in or doing anything. When both my React app and server are hosted, I would make calls to the api and no confidential information (such as passwords) would be sent back to the client (just maybe a "success" message if the login information appears to be correct on the backend). My question is, what is stopping someone from finding the backend route and putting it into Insomnia to get the password or other sensitive information?
My first thought was to use express-session and auth on the backend to require a user to be logged in to an account to make such requests, but I think there are two issues with that:
How will that work when multiple users are logging in at once? Since the users are not technically physically visiting the api routes themselves, does session still know who is signing in to what account on the frontend? Will the second person logging in override the first person's session even though the first hasn't logged out yet?
If the auth doesn't kick in until a person is logged in, wouldn't someone be able to get the response password data from the login route itself?
Sorry if the question sounds dumb I'm just having a little trouble understanding the security aspect.
It sounds like there's a bit of a misunderstanding of how auth sessions work. There are two primary way sessions can work - either storing the sessions on the backend (older way), or storing session data in a cookie, typically a JWT (JSON Web Token). Cookies are bits of data that are passed from the server to the browser and anytime the browser makes a subsequent request to your server, it passes the cookie back too, so your server will always be able to get that data. The way this works for auth is the following:
A user signs into your application with credentials (username and password).
Your server validates the credentials by checking your database or wherever you're storing them and rejects the request if it fails. (Check out Auth0, Firebase Auth, or other auth services as doing this yourself can be a pain and open yourself up to potential vulnerabilities)
If the credentials are valid, the server generates a signed JWT token that includes data, like the username of the user.
The server responds with the body as well as a cookie containing the JWT, which the browser then stores.
The user requests some user-specific data from your server, and the browser sends the cookie with the JWT back to your server.
Your server validates that the JWT is valid by checking the signature. If it is valid, it uses the username from the token to get the user-specific data. If it is not valid, it rejects the request.
Because the signature occurs entirely on the server side (typically with some hashing algorithm and a secret key that you don't vend publicly), it would be nearly impossible for someone to spoof a JWT token signature. Therefor, your server is able to 1. trust that the JWT token is indeed valid if the signature is correct, and 2. find out what user is requesting data.
Here's a video that helps explain and visualize this: https://www.youtube.com/watch?v=soGRyl9ztjI
And here's a library for creating and validating JWTs in Node: https://www.npmjs.com/package/jsonwebtoken
Hopefully that answers your question!

User session between Express+Nodejs and clients using Firebase

what's a common approach of storing user sessions with Nodejs+Express and Firebase auth? I have Android and Ios app that I'd like to use the same logic on (later web as well), so I'd get the JWT token. I'd like to use that token as authorization for requests. Also I'd like to keep the user sessio and not require them to relogin again. I am not sure how to go about this, all of the Express Session resources I've found were on topic of web and cookies. I've stumbled upon MongoConnection a library for Express that presumably stores the sessions in the MongoDb, but how does the session work with non-web requests? Can anyone help me clarify this, I am aware that I am missing the point here as there is certainly an easy way to verify incoming requests and also have a session for the user to not have to login everytime.
Preferably I'd like to have an easy way to have endpoints that require JWT token access. Besides that also have a session of sorts. There is a function to verify tokens in the Firebase Admin SDK for Nodejs but it seems really weird to have to check the token manually in every request.
I treat sessions on the backend and front end entirely separately as I predominantly make RESTful apis. On the front end you can handle sessions however you like, e.g. you can start a session when a user authenticates with firebase auth, and set the user role maybe based of attributes on the firebase auth user. Use cookies, do whatever you prefer.
Then on the backend, on every endpoint just decode the token, verify it, check that the user has access to the resource they are requesting etc. Its common to write your own middlewares so that you dont have to repeat the decoding code. For further info on this approach, this might help. Its not weird to check the token manually on every request, its common practice to guarantee the authenticity of the request. Hope this is of some help.
To sum up, treat your front end session entirely separately from the backend. On your express server on the backend, on any protected endpoint decode and verify the token to determine if the user has access to the resource.
Backend sessions with firebase are a bad idea (due to it been serverless), its better to create a stateless restful api.

PHP REST API Key and User Token Authentication

I wanted to check with you guys if my API Key and user Authentication scheme makes sense or not. My server side code is in PHP and the Database is MySQL. This is the scheme I have in mind:
I am implementing a REST API in a backend server that will be called by a Mobile App (for now). At this point, I only want known Mobile Apps to connect to this API. So I am using a one-time API Key that has been given to the Mobile App during installation. Every request from the App passes the API Key that my API checks before going further. This Key is stored in a Database table. This completes my API Key checking and seems to allow only known Apps from calling my APIs.
Next, I also have certain services after calling the API which only authenticated users are supposed to get access to. For this, the Mobile App logs in with a Username and password which is authenticated in the User table of my Database. If it passes, the server generates a User Token and passes it to the Mobile App. The User Token is also saved in the User table against that User. All subsequent requests from the App (which requires user authentication) passes this User Token which is checked in the User table in the Database for User Authentication. If the Mobile App logs out, this User Token is deleted from the User table. I also have provision to add "TimeToExpire" for this User Token which I will implement later.
I would be really grateful if you guys could tell me the following:
Does the above structure makes sense for App Authentication and User Authentication?
I am a little lost as to what will happen if I ever need to change the API Key (for whatever reason). Not sure how that will be sent to all the Apps. Google Messaging seems like one possible way to handle that.
For the App Authentication, does it make sense to keep the API Key in a Memcached object? Since all requests from the Apps are authenticated, I don't want to go to the DB everytime. And pros/cons?
Along the same lines, does it also make sense to have the User Token in a Memcached object as well? Pros/cons?

Resources