Firebase + Nextjs - User session sharing - reactjs

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/

Related

Get client social signed in user on the server side

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.

Is it ok to pass OAuth access tokens to the Client

i'm still pretty new to web-development I worked myself through Web Development with Node and Express by Ethan Brown and currently i'm trying to get a good understanding for the examples given by Full-Stack React Projects by Shama Hoque.
Currently i'm trying to refactor a lot of things that used to be server-side-rendered to be handled in the React SPA client. One of these things includes a simple GitHub widget, my previous flow worked like this:
The client user authenticates with my server using a GitHub OAuth app.
The server stores the access Token returned to the callback in a database on the server.
The server makes calls to the GitHub API using the user access Token stored in the database.
The server processes the results, renders it in HTML and sends it to the client.
However I realized that there is also possibility to implement it like this.
The client user authenticates with my server using a GitHub OAuth app.
The server passes the access Token returned to the callback back to the client
The client makes calls to the GitHub API using the user access token obtained from the server.
The client processes the results and renders it apropiately.
As far as I understand there is no inherent security risk doing this(a malacious user could interecept the access token when the oAuth provider redirects to the callback either way) and both flows have their up and downsides (e.g. 2nd flow produces less load on the server but also sacrifices control). Since I'm new to this and I came up with the 2nd flow myself I wanna double check if this is something thats ok to be doing or I've missed something, if so, what did I miss? Is there any other major down or upsides i'm not considering?
What you've implemented is the OAuth Authorization Flow. In this flow, the client (aka the browser) never gets the access token. Only your webserver gets it. And thus the client cannot make calls to the resource server (github). Your webserver makes the calls on the client's behalf.
You say:
a malacious user could interecept the access token when the oAuth provider redirects to the callback either way
However, if you implement the flow correctly, this is not true. This is because once you authenticate with the resource server, it only gives the browser an authentication code. This code is just a temporary ticket that can be exchanged for an access token. However, to exchange a code for the access token, you have to know a client secret. Only your web server knows the secret. So your browser sends the code to your server, and your server calls the resource server (github) with the code + secret to get the token.
The second flow you describe is the OAuth Implicit Flow.
This flow is very much what you described: After the user authenticates with the resource server, the browser ends up with the access token and just calls the resource server directly.
Both flows are very common. The Implicit flow is slightly less secure because there is more opportunity for Bad Guys to get access to the token in the browser's memory (or local storage, or cookie storage). The Authorization Flow is a bit more secure because the token stays on your server, and you do not have to depend upon users to keep it secure.

ReactJs How to check user authenticated and sessionID generated by ExpressJs

I have a Nodejs application creating a session when the user gets authenticated.
I see that Expressjs stores the sessionID in a cookie which at the moment is HttpOnly and the session info itself is stored server side.
How to check that the user is authenticated and there is an open session from ReactJS (that is, browser side)?
I think that the only way is to try and access that sessionID? What is a good way of implementing this?
Thanks.
The register or login should respond with the necessary user information to the client side on React so that user information could be stored in the application state (Redux/Flux). The sessionId stored as HttpOnly cookie by express server is solely for the purpose of Express to uniquely distinguish a browser session.
Ideally you would need another API as well to return the user information which at the Express server side should read the sessionId cookie and return with the currentUser information back to the client. Suppose, you login and the user information is stored in the UI application state, and when you refresh the browser, this application state would get flushed off. In such a scenario, this API would help to restore the application state with the current logged in user information. Hope this helps.

angularjs client and spring backend user login and session management

I have a mobile website written in angularjs, with my backend in Spring Boot. Right now, I have my own login page and can login a user without any trouble. However, if the user ever clicks "back", "refresh", etc., the client loses the user's id and login info (obtained from server on login). I need to make sure that this info is maintained and clicking "back" or "refresh" doesn't break everything.
Secondly, a user that knows the url's after login can type those url's in the browser and access them without logging in. I can stop them accessing anything on the server, but not sure what I can do on the client to redirect them to a login page in this case.
Any help would be greatly appreciated!
You should keep in mind that everything running in browser is stateless, there's no way to keep trace of the previous state.
Right now, if the user performs a refresh (or another similar action), Angular loses everything (AuthData included).
You have many way to work around that limit:
Perform an http request after the application bootstrap (have a look at the angular.module().run method
Save a cookie and use the server to print initial data layer directly on the dom via json
Save on local/session storage
Personally, I prefer cookies because that lets the server to work decoupled from the client.
In reference to your comment..."if the user ever clicks "back", "refresh", etc., the client loses the user's id and login info (obtained from server on login)."
Is there any reason you need to maintain the user id or login info after a successful authentication?
If Spring Security is setup for basic authentication, after a successful login, a Session Cookie will be sent back on the response to the client. On all subsequent requests to the server, the same Session Cookie will be sent on the request and the previously authenticated session will be re-established. You just need to ensure that your Angular client is passing cookies when issuing requests.
Take a look at this sample on how this is done.

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