DEV Community

Cross-Domain Firebase Authentication: A Simple Approach

Brian Burton on February 15, 2021

If you're reading this you've probably just discovered that Firebase Auth only authenticates for a single domain, yet you need to share that authen...
Collapse
 
mfbremotesocial profile image
Mike Fitzbaxter (MFB)

We've built a version based on the original post by John Carrol you link above and are struggling with complex logic that is periodically causing logouts for new users. We are using the __sesion token but also making use of the suggested CSRF cookie. Are you aware of any security implications to you having omitted that step recommended by John Carrol in his linked post? I would love to simplify the logic we are using and remove additional steps if they are not required.

Collapse
 
brianburton profile image
Brian Burton • Edited

John's approach is solid and if implemented correctly should be secure. The above approach I'd call a refinement. The primary improvements here are using a single Firebase session cookie across all domains for stateless JWT authentication and no cross-domain requests.

The CSRF protections should be implemented no matter what, I didn't include that because it seemed out of scope however just making an httpOnly __session cookie and strict a strict single-domain CORS policy on the /auth/* endpoints would make any XSS attack difficult. The only change I would recommend from his approach would be to pass the CSRF token with a custom HTTP header and not a cookie, but that's splitting hairs.

Also if you're not using Firebase session cookies that may be the cause of your users getting randomly logged out.

Collapse
 
mfbremotesocial profile image
Mike Fitzbaxter (MFB)

Thanks for following this up. I'll double check the __session cookie we are assigning, it could very well be that it's not the Firebase session cookie.

Collapse
 
johncarroll profile image
John Carroll • Edited

Interesting. But wouldn't calling revokeRefreshTokens(<uid>) sign the user out of every browser and every device? Not just the browser/device they are trying to sign out of?

Collapse
 
brianburton profile image
Brian Burton • Edited

Yes unfortunately it's a nuke 'em all approach, but alternatively the client could monitor the presence of the __session cookie and log the user out client side on each subdomain if it's missing.

Updated the last step to show how to revoke a user's authentication across all devices or just the current device.

Collapse
 
thammada profile image
Thee Sritabtim

Interesting approach. At step (I.2) do you suggest POSTing the ID Token inside the http body to app1.domain.com/auth/login? If so, how is it different from POSTing it to a http cloud function directly (possibly hosted on auth.domain.com)?

Collapse
 
brianburton profile image
Brian Burton • Edited

For your first question, yes I POST the ID token inside the body to /auth/login.

For your second question, the /auth/login endpoint checks and sets a session cookie for that domain, so it needs to be on the same domain. Another minor benefit is that it also avoids potential CORS errors.

Collapse
 
lingdocs profile image
LingDocs • Edited

This looks really great but I understand that with createSessionCookie() the maximum expiresIn value you can set is two weeks? That means that users would have to sign again every two weeks correct? It's too bad they don't allow for longer cookies.

Perhaps one could do this to extend the cookie, but that would only work if the user is using one of the subdomains more than once every two weeks. 🤔

Collapse
 
brianburton profile image
Brian Burton • Edited

When the user hits /auth/status you can always refresh the token and update the session cookie.

Collapse
 
juancarvajal profile image
Juan David Carvajal Hernandez

Hi! Very interesting post, I have been trying to implement this with 2 Firebase apps from the same project, I am pretty sure that it'll work in production (if both apps run on the same domain) but I am having a lot of problems getting this to run locally. Modern cookie setting for Chrome and most browsers prevent cross-site cookies from going through insecure connections, as of today, there is no way to run the emulators on HTTPS. I tried using self-signed certificates on localhost but the browsers won't allow HTTPS even with that (even with chrome://flags/#allow-insecure-localhost set to enabled in Chrome). At the end all this means that app 1 is setting the cookie, but the browser is never sending it to app 2. Any suggestions? Did you ever got this to work locally?

Collapse
 
brianburton profile image
Brian Burton

For local dev it may be easier to add some code to determine if it's running locally and then just faking the session. Perhaps you could set up a reverse proxy in front with nginx. Not sure if it'll work with the firebase local environment but worth a shot.

Collapse
 
eleventhaus profile image
Faro

Are there any code examples for this?

Collapse
 
brianburton profile image
Brian Burton

No I never put together a proof of concept example, but honestly I didn't expect so many requests for an example

Collapse
 
sanujbansal profile image
sanuj bansal

But why do we need to create custom token, can't we simply validate the requests using verifySessionCookie() each time we get a request?

Collapse
 
brianburton profile image
Brian Burton

Two tokens for two different purposes. The custom token that you generate is for client-side authentication using the firebase library in the browser. You can authenticate the visitor using the session cookie for server-side requests, but the firebase client-side library in the browser won't know who the person is.

Collapse
 
kevinmmansour profile image
Kevin M. Mansour

If you add simple Code to this Idea .. I will be appreciated :)

Collapse
 
holgersindbaek profile image
Holger Sindbaek

Thanks for the example. I was wondering if it works for separate domains like domain1.com and domain2.com or if it only works for sub-domains?

Collapse
 
brianburton profile image
Brian Burton

For multiple TLDs you'd need use a SAML-style flow.

Collapse
 
tjob3285 profile image
Tyler Job

Have you cooked up any code examples?