Which is the correct way to persist Firebase Session after cookie expires? - node.js

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.

Related

Regenerate auth token

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.

getstream chat: Using a new JWT token for each server side request

Following the GetStream chat API docs I've been wondering if there's any disadvantage in sending a newly signed token with each server-side API request.
That way my server will remain stateless and will allow me to generate very short lived tokens.
Generating a new token for server-side for each request doesn't make much sense because server-side has already full access since using API secret.
If you have multiple API keys, then having the same number of tokens with their respective secrets sounds fair. Here, we assume this is a secure environment because it uses secret to do anything on your account.
If you check server-size SDKs (Go, Python, etc), when you create a client, they actually generate your token and cache it.
However, client side is a different story. JWT is stateless but probably your app needs (session) state management and expiration should be done (logout for example). In this case, 15 mins to expire a token and refresh token under the hood is a pretty common practice.
Short JWT expiration
pros:
no need for central storage (blacklisting for logout, password change, etc)
more secure (changed more frequently even if stolen)
cons:
more processing time/resource are spent to sign a new token (cryptography is slow)
more network requests for refresh
bad user experience if token isn't saved, instead kept in memory (needs login and security might be a problem on saving since token could be stolen otherwise)

JWT Token strategy for frontend and backend

I'm writing an application with a front end in emberjs and backend/server-side in a nodejs server. I have emberjs configured so that a user can login/signup with an 3rd party Oauth (google, twitter, Facebook). I have a backend written in express nodejs server that hosts the RESTful APIs.
I do not have DB connected to emberjs and I don't think I should anyways since it's strictly client side code. I'm planning on using JWT for communicating between client side and server side. When a user logins with their oauth cred, I get a JSON object back from the provider with uid, name, login, access_token and other details.
I'm struggling with picking a strategy on how to handle user signup. There is no signup process since it's OAuth. So the flow is if the user is not in my db, create it. I do not support email/password authentication. What would be the flow when a user signs in with an OAuth provider for the first time? Should emberjs send all the details to the backend on every sign in so that backend can add new users to the db?
What should be part of my JWT body? I was thinking uid and provider supplied access token. One issue I can think of here is that provider specific access token can change. User can revoke the token from provider's site and signs up again with emberjs.
I'm open to writing the front-end in any other javascript client side framework if it makes it easier.
If we're talking about not only working but also secure stateless authentication you will need to consider proper strategy with both access and refresh tokens.
Access token is a token which provides an access to a protected resource.
Expiration here might be installed approximately in ~1 hour (depends on your considerations).
Refresh token is a special token which should be used to generate additional access token in case it was expired or user session has been updated. Obviously you need to make it long lived (in comparison with access token) and secure as much as possible.
Expiration here might be installed approximately in ~10 days or even more (also depends on your considerations).
FYI: Since refresh tokens are long lived, to make them really secure you might want to store them in your database (refresh token requests are performed rarely). In this way, let's say, even if your refresh token was hacked somehow and someone regenerated access/refresh tokens, of course you will loose permissions, but then you still can login to the system, since you know login/pass (in case you will use them later) or just by signing in via any social network.
Where to store these tokens?
There are basically 2 common places:
HTML5 Web Storage (localStorage/sessionStorage)
Good to go, but in the same time risky enough. Storage is accessible via javascript code on the same domain. That means in case you've got XSS, your tokens might be hacked. So by choosing this method you must take care and encode/escape all untrusted data. And even if you did it, I'm pretty sure you use some bunch of 3rd-party client-side modules and there is no guarantee any of them has some malicious code.
Also Web Storage does not enforce any secure standards during transfer. So you need to be sure JWT is sent over HTTPS and never HTTP.
Cookies
With specific HttpOnly option cookies are not accessible via javascript and are immune to XSS. You can also set the Secure cookie flag to guarantee the cookie is only sent over HTTPS.
However, cookies are vulnerable to a different type of attack: cross-site request forgery (CSRF).
In this case CSRF could be prevented by using some kind of synchronized token patterns. There is good implementation in AngularJS, in Security Considerations section.
An article you might want to follow.
To illustrate how it works in general:
Few words about JWT itself:
To make it clear there is really cool JWT Debugger from Auth0 guys.
There are 2 (sometimes 3) common claims types: public, private (and reserved).
An example of JWT body (payload, can be whatever you want):
{
name: "Dave Doe",
isAdmin: true,
providerToken: '...' // should be verified then separately
}
More information about JWT structure you will find here.
To answer the two specific questions that you posed:
What would be the flow when a user signs in with an OAuth provider for
the first time? Should emberjs send all the details to the backend on
every sign in so that backend can add new users to the db?
Whenever a user either signs up or logs in via oauth and your client receives a new access token back, I would upsert (update or insert) it into your users table (or collection) along with any new or updated information that you retrieved about the user from the oauth provider API. I suggest storing it directly on each users record to ensure the access token and associated profile information changes atomically. In general, I'd usually compose this into some sort of middleware that automatically performs these steps when a new token is present.
What should be part of my JWT body? I was thinking uid and provider
supplied access token. One issue I can think of here is that provider
specific access token can change. User can revoke the token from
provider's site and signs up again with emberjs.
The JWT body generally consists of the users claims. I personally see little benefit to storing the provider access token in the body of a JWT token since it would have few benefits to your client app (unless you are doing a lot of direct API calls from your client to their API, I prefer to do those calls server-side and send my app client back a normalized set of claims that adhere to my own interface). By writing your own claims interface, you will not have to work around the various differences present from multiple providers from your client app. An example of this would be coalescing Twitter and Facebook specific fields that are named differently in their APIs to common fields that you store on your user profile table, then embedding your local profile fields as claims in your JWT body to be interpreted by your client app. There is an added benefit to this that you will not be persisting any data that could leak in the future in an unencrypted JWT token.
Whether or not you are storing the oauth provider supplied access token within the JWT token body, you will need to grant a new JWT token every time the profile data changes (you can put in a mechanism to bypass issuing new JWT tokens if no profile updates occurred and the previous token is still good).
In addition to whatever profile fields you store as claims in the JWT token body, I would always define the standard JWT token body fields of:
{
iss: "https://YOUR_NAMESPACE",
sub: "{connection}|{user_id}",
aud: "YOUR_CLIENT_ID",
exp: 1372674336,
iat: 1372638336
}
For any OAuth workflow you should definitely use the passportjs library. You should also read the full documentation. It is easy to understand but I made the mistake of not reading the the whole thing the first time and struggled. It contains OAuth Authentication with over 300 Providers and Issuing Tokens.
Nevertheless, if you want to do it manually or want a basic understanding, here is the flow that I'd use:
Frontend has a login page listing Sign-in with Google/Facebook etc where OAuth is implemented.
Successful OAuth results in a uid, login, access_token etc. (JSON object)
You POST the JSON object to your /login/ route in your Node.js application. (Yes, you send the whole response regardless if it's a new or existing user. Sending extra data here is better than doing two requests)
The backend application reads the uid and the access_token. Ensure that the access_token is valid by following (https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken) or asking for user data from the provider using the access token. (This will fail for invalid access token since OAuth access tokens are generated on a per app/developer basis) Now, search your backend DB.
If the uid exists in the database, you update the user's access_token and expiresIn in the DB. (The access_token allows you to get more information from Facebook for that particular user and it provides access for a few hours usually.)
Else, you create a new user with uid, login etc info.
After updating the access_token or creating a new user, you send JWT token containing the uid. (Encode the jwt with a secret, this would ensure that it was sent by you and have not been tampered with. Checkout https://github.com/auth0/express-jwt)
On the frontend after the user has received the jwt from /login, save it to sessionStorage by sessionStorage.setItem('jwt', token);
On the frontend, also add the following:
if ($window.sessionStorage.token) {
xhr.setRequestHeader("Authorization", $window.sessionStorage.token);
}
This would ensure that if there is a jwt token, it is sent with every request.
On your Node.js app.js file, add
app.use(jwt({ secret: 'shhhhhhared-secret'}).unless({path: ['/login']}));
This would validate that jwt for anything in your path, ensuring that the user is logged-in, otherwise not allow access and redirect to the login page. The exception case here is /login since that's where you give both your new or unauthenticated users a JWT.
You can find more information on the Github URL on how to get the token and to find out which user's request you are currently serving.

Node Js refresh auth token

How can you provide example for refresh node js auth token? I mean by what the parameters can I refresh auth token? For example if I can refresh it by login and password then where should I store this params for single-page app? As I understand store it in cookie is not good idea for security, localstorage is not good also because some of browsers not supported it. So maybe someone know another way for refresh token?
Cookies are a very secure storage mechanism, if used correctly. Local storage should never be used for authentication information. OWASP has a great write-up on storage security:
https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Storage_APIs
To quote the important parts:
Do not store session identifiers in local storage as the data is always accessible by JavaScript. Cookies can mitigate this risk using the httpOnly flag.
[With local storage] There is no way to restrict the visibility of an object to a specific path like with the attribute path of HTTP Cookies, every object is shared within an origin and protected with the Same Origin Policy. Avoid host multiple applications on the same origin, all of them would share the same localStorage object, use different subdomains instead.
Back to your original question: where to store the refresh token? Answer: In a HttpOnly cookie. This prevents the cookie from being stolen by XSS attacks, and it makes it very easy for your server to issue new access tokens (using the refresh token) because the server will have access to both at the same time, on the same request.
You can add another layer and encrypt the entire refresh token that is stored in the cookie.
Caution: when using cookies, you also need to protect yourself against CSRF attacks
I’ve written at length about front-end security and JWTs in these two blog posts:
Token Based Authentication for Single Page Apps (SPAs)
https://stormpath.com/blog/build-secure-user-interfaces-using-jwts/
Disclaimer : I work at Stormpath, our service gives you a secure, hosted user database with many features. Our express-stormpath module makes it very easy to get started with login and registration flows for your application. We are in the process of writing a new release, and it will be using access tokens in the way that I describe in this answer.
I created AuthToken model that contain these fields:
user_id, access_token, refresh_token, access_token_expiration
After successful user login, server side will send refresh_token and access_token to client side and store it to localstorage(cookies for old browsers).
And all subsequent requests will be sent with access_token(I use header x-access-token for $httpProvider in angular).
When token expires, client needs to send refresh_token for updating access_token, refresh_token and expiration date. Since I use sockets I can refresh access_token if it is expired in any request(for this I send z-refresh-token header also for each request) so I shouldn't send any extra request and I can keep current user request, just will return tokens via socket event after it was updated.
Hope this helps

Store the oauth access_token or ask a new one each 'session'

I'm playing around with the api of a service that supports oauth. I managed to retrieve the access_token from the service and I'm now able to call the various endpoints of the api. So far so good.
Now my question is: How long do I hold on to this access_token I received. Is this a token I keep forever, or does this expire after some time? I'm working on a desktop app, so I a have two options:
I request a new token every time the application is opened
I store the token somewhere and re-use it
What are the best practices around the storage of this token?
Usually the Access Token is stored across sessions. There is an expiration (with OAuth 2.0), but the Refresh Token is then used to retrieve a new Access Token. If you don't store the tokens, then you would need to have the end user re-authorize everytime they want to use your application (which is probably not the experience you are looking for).

Resources