Get client social signed in user on the server side - reactjs

I am using NextAuth to sign in users using Facebook or Twitter. This works fine and I get the AccessToken along with basic user info. On the server I am using the socialId of the logged in user to map to the corresponding local user in the database. Azure Functions has a social login feature called EasyAuth but I am not sure if I need it since I am using NextAuth. I was thinking of two ways:
Send the loggedin user object with every request? This is probably not save?
Send the access token with every request and the server calls the corresponding social api to get the user info again?
What would be a good practice security vice when sending the information to the server?

The client should not be aware of who is currently logged-in. On the client, you just save the access token, and then you send it to the server on every request. The server will figure out who made the request based on the access token and return the appropriate response.

Related

Firebase Auth, after logging a user from react client, how do I verify user is legitimate within my other api?

I'm trying to use Firebase authentication to sign up and login users for my react website, but after that, how do I ensure that actions made from my nodejs api (for instance creating/modifying articles) are from that logged-in user. Here's a situation:
User logs in on my website, the firebase.auth().signInWithEmailAndPassword() method is called directly by the client within react (I can't use that method on my api since it asks for the raw password and I don't want to be sending that across the web, though I could save a salt on my db and hash the password, etc. but the reason I'm using firebase auth is to avoid having to be hashing passwords and maintaining salts on my db)
User is confirmed logged in
User starts to create an article
They submit the created article, react verifies they are logged in with firebase.auth().onAuthStateChanged()
Article data is sent to my api, for instance POST somehost.com/myapi/article/create/ with the article data in the body
My api receives the request and saves the article to my database
The problem I see here is that I don't see a way to send credentials to somehost.com/myapi/article/create/ in order to verify the user before entering the article into my db, since all signup/login is done within react and firebase's auth functions don't return anything I can send to my api to verify, so essentially anyone can call that endpoint and flood my database with junk.
I would like to be able to login the user within react, but then verify the user is legit within my api for all calls the user makes to it before it sends anything to the db. How can I do this?
If your Firebase client app communicates with a custom backend server, you might need to identify the currently signed-in user on that server. To do so securely, after a successful sign-in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity and authenticity of the ID token and retrieve the uid from it. You can use the uid transmitted in this way to securely identify the currently signed-in user on your server.
See https://firebase.google.com/docs/auth/admin/verify-id-tokens

How to read users gmail after receiving push notification from gmail users.watch API?

I want to implement a backend server that can read (to perform some action) users gmail every time a new mail is received. I am able to figure out that using gmail API users.watch, my server can be notified every time a new email is received. Now, for fetching new mails from gmail my server needs User credentials (Auth token) that are provided by the user at the time of opting in to be watched. Is there anyway these credentials can be sent to my server along with the push notification (maybe using users.watch API).
One method I came across to achieve the same is to store auth and refresh token in a DB, that will be accessible only by my server. But it will be better if the purpose can be achieved without storing credentials in the DB.
When the user authenticates your application you are given a refresh token assuming that you requested offline access. You should store this in a secure place associated with the user on your server.
When you get a push notification you should then retrieve the refresh token that you have stored on your server and use that to request a new access token that you can use to access the users data.
The push notification system has no way of sending you the authorization nor would it be a very wise idea if it was storing your authorization.

reactJs secure storage

I'm a back-end developer who has to create the front-end too in the current project!
I'm using reactJs and I know that for authorizing users I should get an api_token from my back-end API then use the api_token in the next requests! so I should store the api_token (actually somewhere into the client's browser)! but where should I store it to be secure?
the first answer came to my mind was 'Local Storage' ! but I've read this article: Don't store tokens in local storage
I've searched and found #auth0/auth0-spa-js, but I don't know can I trust this package (and similar) or not?
these are the way's which I've found! but what's the correct way to store sensitive data like this?
The Auth Flow should be on the Web should be
Send User/Password Details to server
Server validates and returns encrypted token with some details inside and that's stored as a HTTP Cookie
Setup Protected endpoints so only users with token can access them
Security : HTTP Cookie only means that the browser doesn't have access to it on the client, only the server. But someone can simply just Copy Paste it into their cookies which if you're worried about or working on sensitive stuff, you will need to implement additional security measures such as the ones mentioned.
Generally, Device Management is not a web concern but you can also some validation on the token for things like make the token expire in 5 minutes, or expire on session end, DeviceId, Browser Id, IP address, send them an email that a new unknown IP has logged in, etc.
Never store private tokens in your frontend code
You should create a server that can only be accessed from a particular url (the url of your app). This server can have the secret tokens that you need to make calls. The that server can forward requests to the services you will use that need private tokens.

Firebase + Nextjs - User session sharing

Problem:
I need to make database requests on the server side of my app which is written using Next.js and Firebase (not the best combination, I know) to prepare initial data for the client side.
Problem is that I would like to use the same code that runs on the client side on the server (using the firebase client SDK on the server for the DB requests).
But I do not know how to share the user session with the server side.
The server does not have the user logged-in in the client SDK and thus returns 403 for restricted resources even though the client side has access to them (it knows the current user)
I have tried the following:
Custom token hack (can´t use ID token to sing in)
Currently I have to add the user ID token to a cookie.
This way the token is appended to every subsequent request and the server side can generate a custom token (I cannot login with the ID token) through which I can then login on the server side of the app as well as on the client side (which is already logged-in if persistence is enabled).
This is a huge overkill and I should be able to login on the server the same way as on the client because it is in fact acting like a client itself (it does not do any privileged operations).
Login second time on the server
Other solution was to send credentials via cookie (security risk) and then login on the server second time. This does not work with one time auth sessions (like one-time email links because the server effectively logs in the second time).
The official expample is not helpful
In the Next.js repo there is a example for firbease auth which has now commented out the server side data fetching. Even if it was not commented out it is not checking for user permission, it just straight up fetches the data if a user is found https://github.com/zeit/next.js/tree/canary/examples/with-firebase-authentication
I was having the same setup (Next.js and Firebase) and it was not straightforward setting up global session via react context API. I followed this guide and I was successful https://reacttricks.com/sharing-global-data-in-next-with-custom-app-and-usecontext-hook/

Firebase auth state persists on client, but not on hard refresh

I'm building an isomorphic React app that uses Express to handle server requests.
When running the bundled React app on the client side, my Firebase login flow works nicely:
I login using Firebase's email/password option
After authentication, ref.getAuth() successfully returns the user's auth object
Subsequent calls to ref.getAuth() while navigating through my app client-side (via react-router) also return a successful auth object.
However, hard refreshes (which would come from the server) don't persist, even after a successful login on the client. Using the same React components in a server context, ref.getAuth() returns null.
Am I missing a step to make this work on the server in the same manner it works on the client (with the use case being a hard-refresh of the site)?
If you're connecting to Firebase on the server as part of your isomorphic/universal rendering (which I assume you are), Firebase has no way of knowing which user initiated the request to your server that then subsequently issued the request to Firebase—on the client, the user's cookies can be sent along to Firebase, but it's your server, not the client, that's initiating the request on the server, and so is not associated with any given user.
My first thought was, in order to send authentication from the server, you'll need to have some sort of login on your own server; once you verify (with Firebase or otherwise) that the user is who they say they are, you can generate a token that you can save (securely) in the user's session and also send back to the client. Then, on the client, and on each server request, just before rendering your React application with React.render*, you would call authWithCustomToken() with that user's token.
The one caveat, however, is that authentication to a Firebase database is global—when you authenticate a Firebase ref (even in Node.js), every single other ref pointing to the same database gets authenticated with those credentials; you can't log in as different users by using separate refs. So, if your React rendering pipeline on the server does any asynchronous operations between when the auth callback is called and the app is rendered (e.g. if you use something like react-async or do other fancy async data loading before rendering), the user that is authenticated against your Firebase might have changed by the time you go to render your application. If, however, your rendering pipeline is purely synchronous, you should be able to get away with this strategy (getAuth() can help ensure that you have the right auth before you render).
Aside from that, I think the most straightforward solution is the following:
Authenticate your users through your own server, creating a secure token and passing it back to the client for authentication purposes. Store this token in the user's session so the client can request it and auth with it on the client as necessary. You'll also need to generate your own auth data (the stuff that is normally passed to the callback for authWithPassword) and store this in the session as well.
For server requests to your Firebase, use one of the recommended server authentication schemes:
Using a Firebase app secret: All authentication methods can accept a Firebase app secret instead of a JWT token. This will grant the server complete read and write access to the entire Firebase database. This access will never expire unless it is revoked via the App Dashboard.
Using a secure JWT with the optional admin claim set to true: This method will grant a server complete read and write access to the entire Firebase database. This token will expire normally, so it is important to set the expiration times accordingly.
Using a secure JWT designed to give access to only the pieces of data a server needs to touch: This method is more complicated, but it is the safest way to authenticate a server as it lets the Security and Firebase Rules prevent the server from doing anything it's not supposed to, even if it becomes compromised in some way.
Include server logic to ensure that the current logged in user can only access appropriate data. Since the above methods of authentication will grant access to data the user may or may not have access to, you'll need to take your own steps to ensure that users don't get accidental access to things they shouldn't.
Pass the auth data that you stored in the session in step one to the React application as a property, instead of relying on things like ref.getAuth() to get this data inside your React app (since it won't work on the server), to identify the user in your UI.

Resources