Regenerate auth token - node.js

I have a flutter app with a node.js backend api. I'm using firebase Auth for authentication. The way it works now (which I don't know is standard,) is the user sends a request to firebase auth to login/signup. The jwt gets stored in the flutter app, then it sends that firebase jwt to my API, which verifies it's a valid token firebase.auth().verifyIdToken(), and my API sends over a new jwt created with firebase firebase.auth().createCustomToken(...) with custom info.
Before every response my API sends over, it checks if the custom jwt was created after 15 min. If it was, it recreates a new custom jwt. If it passed 7 days since it's original creation, it logs out the user.
The problem is, I don't see a way to regenerate a firebase auth token on the server. Which means every hour the user will have to re-login.
I feel I'm overcomplicating things, but I'm not sure of a better design of doing this. Is there a standard? How can I make this better and how can I make it that the user doesn't have to re-login after just 60 min?

The custom tokens created by createCustomToken() are used when you have a third party auth system but you want to login your users with Firebase auth.
The problem is, I don't see a way to regenerate a firebase auth token on the server. Which means every hour the user will have to re-login.
You don't have to do anything on the server. Every time you need to call your API, you can use getIdToken() to get user's ID token.
var token = await FirebaseAuth.instance.currentUser().getIdToken();
This will return user's current token and if it has expired then it'll a refreshed token. You can then pass the result to your API. There's no need to explicitly store the token anywhere yourself.
Whenever you are making an API request, the flow could be as simple as:
Get user's ID Token using getIdToken()
Pass this token in your API request
Verify it using verifyIdToken() and return the response.

Related

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.

Which is the correct way to persist Firebase Session after cookie expires?

I've been dealing with authentication, reading and watching videos about it. I came up building my own JWT solution, based on an access_token who expires after five minutes, and a refresh_token that never expires. I stored that tokens in cookies and I use the second one to provide more access_tokens when needed. I store the refresh_token in Redis, to be able to revoke if one of those is leaked / stolen.
Nowadays, I need to move my auth system to Google Firebase in order to store my users there, and to add the Google and Facebook login as well. But I found that I need to create a sessionCookie that expires in, as much, two weeks. After that, the user is signed-out from the app and it needs to access again manually. I want to refresh that firebase sessionCookie in the correct way (automatically, server-side), but the docs say nothing about it. I came up doing my own solution again, but I believe it is not right.
I don't want to use the getIdToken method because, with that thing of custom tokens, I need to modify each of my api calls in the client side, and that's not the idea. I want to do the refresh at server-side.
So, which is the correct way to refresh the sessionCookie automatically and to keep the user authenticated permanently?
Info that I read here:
How to Refresh Firebase Session Cookie (stackoverflow)
How to extend Firebase Session Cookie Beyond 2 weeks? (stackoverflow)
Refresh Tokens (by Auth0)
JWT Auth with Node.js (youtube)
Server-side Firebase Authentication Using Express JS (youtube)
And, of course, the official docs from Google Firebase
Firebase session cookies expire in an hour, to my knowledge this cannot be modified or changed. the main takeaway should be why you would need a token to expire after 2 weeks rather than demand it on a per need basis from the Refresh token?
The solution is to generate a custom JWT token and store it online(optional) and pass it to the client. The client then uses this key for long-term authentication. this does mean that all requests would have to be validated and decoded within your backend, the only issue from there would be local caching, which can be done in several ways including standard local storage and cookies.
The flow would be: Firebase Refresh token -> Generate Firebase Auth ID Token -> Get user.uid -> Load custom JWT from storage or Generate a new jwt from the admin-sdk.
From the Admin SDK documentation with custom auth, these 3 topics are of interest.
https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_the_firebase_admin_sdk
https://firebase.google.com/docs/auth/admin/create-custom-tokens#sign_in_using_custom_tokens_on_clients
https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_a_third-party_jwt_library
The only thing to figure out is how you want to store the jwt client side.

Google Sign Flow for Website. IDToken vs Access Token. Which one do I need?

What I ideally want to achieve is to be able to Login with Google SignIn, and put authentication on my Nodejs server's endpoints.
What I have done till now is log in the user in the browser, and send the IdToken to the server, validate this TokenId using verifyIdToken() using this link.
https://www.google.com/search?q=verify+idToke&rlz=1C5CHFA_enIN936IN936&oq=verify+idToke&aqs=chrome..69i57j0i13l2j0i13i30l3j69i60l2.12008j0j7&sourceid=chrome&ie=UTF-8
Question:
Once verified, should I generate an access_token using some package, and use that to secure my server's API? Or Use Google SignIn's IdToken as an access token for it?
Or Is there some other flow I'm not getting?
The id_token contains information about the user i.e. email, name, and profile picture.
If that's all that your application needs then the access_token won't be of use to you.
If you're trying to access/modify data belonging to the user, (i.e. trying to add an event to their calendar using the calendar api) then you need the access_token. The access_token is what will give you access to the user's account. If your application requests offline access to the user data then you will also receive something called a refresh_token that will let you regenerate your access token once it expires. If you add the refresh token to your oAuthClient it should automatically renew the access token for you when you make an api call.
Based on what you described I don't think you need the access_token and the id_token might be all you need.
More information is available on this page: https://developers.google.com/identity/protocols/oauth2

How should I handle RESTful authentication while using JWT tokens?

I have read many articles and viewed many videos but there are a lot of contradictions. I try to avoid any external libraries and build the system from scratch, I have read about oAuth 2 but it is more confusing.
This is the flow that I think is ok untill now:
User fills a form using email and password and submits it.
Server verifies the password if it matches and responds back with a httponly cookie with a signed jwt token that expires in like 10
minutes. (I know I have to protect it against csrf attacks)
User gets logged in and every new request he is making to the server he will send the cookie in the header automatically and the
server will verify the token.
Everything is fine but I have encountered some issues and have some questions:
I want the user to stay logged in even after opening a new session so there is no need to login after the token expired or when he closes the browser.
What should happen if the access token expired?
There should be a refresh token attached to the user in database that gets added when the user logs in with an expiration of ex 7 days, then the server will respond with a cookie containing that refresh token?
On the new request while access token is expired,the user will send the refresh cookie to the server, if it matches the user database refresh token,server will respond with a separate cookie that will renew the access token?
If there is a refresh token where should you store it and what format? (cookie,database or where?)
Should I keep the user logged in based on this refresh token cookie?If is it httponly I can't read it and set the state that user is logged in. How should I do it?
I heard about that revoking the jwt token is problematic. How would you fix it?
How would you do this whole thing?Please explain the workflow, I try to avoid localstorage,as I read everywhere that is not safe for sensitive data.
I have implemented and deployed to production systems that do exactly the kinds of things that you are asking about here so I think that I am qualified to provide you with some guidance to solve your particular issues and answer your questions. The flow that you have listed above in the numbered list is definitely the correct path so far. I do understand your confusion going forward from there because there are many different options for how to approach this problem.
In addition to providing a login route that returns a new JWT to the client when the user submits a login form to the server, I would recommend also implementing a token refresh route that accepts a still valid JWT that was received from the initial login process and returns a new JWT with an updated expiration time. The logic for this new token refresh route should first verify that the provided JWT is still valid by matching it with a user in the database. Then, it should generate a new token using the same JWT generation logic as the login route logic. Then, the application should overwrite the access token data in the database for the user replacing the old access token with the newly generated access token. It is not necessary to keep an old access token in the database once it is no longer valid, which is why I suggest simply overwriting it with a new one. Once all of that is finished and successful, you can return the new JWT to the client and then the client should now use that new JWT when making any additional authenticated calls to the server to maintain an authenticated interaction with the server. This logic flow would keep the user logged in, because the client would have a valid JWT before calling the refresh logic and it would have a valid JWT after calling the refresh logic. The user should only be recognized as not logged in and not authenticated if they are no longer able to provide a valid access token that is associated with a user in the database.
As far as cookies go, whichever method that you use for maintaining the cookies on your client should be used for setting the refreshed access token as it is for setting the initial access token that you receive on login. If the server finds that an access token is no longer valid at some point in the future, if for example your client is not used after login until some time after the access token has expired, then the client should recognize a server response indicating that this is the case and present the user with the login flow on the client again so that a new access token can be acquired and stored in a cookie on the client.
I would not worry about revoking JWTs and instead just let them expire if they do and initiate a new login flow if it is found that a JWT has expired. Also, instead of using local storage I would suggest using session storage to store your JWT so that you have it for the duration of your user's session on the website and it is removed as soon as the browser has been closed. This will prevent the JWT from persisting beyond the session and should assuage your fears about saving sensitive data in the session storage. Also, when generating your JWT, you should also make a point of not storing any sensitive data in it because JWTs are easily reverse-engineered. This can also prevent any sort of sensitive data from being exposed on the client.
EDIT:
The key thing to remember when developing your server API is that you should have two different classes of endpoints. One set should be unauthenticated and one set should be authenticated.
The authenticated set of endpoints would not require an access token to be included in the request. An example of this class of endpoint would be your login endpoint, which does not require an access token because it actually generates an access token for you to use later on. Any other endpoint that does not expose sensitive or important information could be included in this class of endpoints.
The unauthenticated set of endpoints would require an access token to be included in the request, and if no access token or an invalid access token is detected the endpoint would respond with a 401 HTTP response code (indicating an unauthorized request). An example of this class of endpoint would be an endpoint that allows a user to update their personal information. Obviously, a user cannot update their own information if they cannot provide credentials to prove that they are the user whose information they are attempting to update. If the client receives a response with a 401 response code, that would be the signal that the client would need in order to tell the user to re-login so that a new valid access token can be retrieved. This possibility can be avoided on the client if the client is programmed to periodically check the expiration of the JWT that is currently being held on the client and initiate an access token refresh, but obviously you should still have logic in place to detect and respond to a 401 response code so that the client user flow is managed properly.

How to combine node express with passport providers and jwt?

I'm writing a single page web app using express and react.
I am now trying to choose the way to authenticate my users.
I want to let them register and log in with email and password and 3rd party provider like Facebook, Google etc...
I read some articles about passport and jwt (express-with-passport, jwt-with-passport), but none of them combined jwt and 3rd party provider.
The only way I could think of is to save the tokens in my db, and for each request to compare them (tokens provided by a 3rd party and tokens generated by myself using jwt)
Saving the token from a provider in my db and compare with each request makes sense, but using jwt I just need to verify the token without accessing the db.
How can I differ the tokens that I receive from the client? How can I tell when to access the db (for provider tokens) and when to verify using jwt?
EDIT:
The way of implementation I was thinking about is as follows:
- Username & password: Upon login, generate a token (using jwt) and send it to the client. Every request will include the token and the server will verify it.
- 3rd party provider: Let's say that the user is authenticated with Facebook. My server receive the token (using passport-js) from Facebook. Now I need to send the client its token. I could send the token I just received from facebook, but then how can I verify the token the client send to me afterward on every request?
So I could generate once again a token using jwt and work just like described above.
Is this a good implementation or am I missing something? I couldn't find
a full tutorial that describe all of those aspects.
Rather than using a token that an identity provider might give you, you might consider generating your own tokens based on a successful login callback to your application. Issue new tokens on every request for sliding expiration, and possibly consider the use of refresh tokens.
In your DB, you could store the authentication method for a given user (Facebook / Google / etc.) when they log in. When you receive a request with an invalid token, query for this auth method from the DB, then redirect them to the respective identity provider for re-authentication.
This will avoid DB lookups for most "normal" JWT validations for your app and gives you the full benefits of the stateless nature of the token.

Resources