DEV Community

loading...

Cross-Domain Firebase Authentication: A Simple Approach

Brian Burton
Updated on ・2 min read

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 authentication across domains and subdomains and not sure where to start.

I was in the same boat and discovered one developer's approach that helped to point me in the right direction. Here is a simpler approach that's just as secure but with less plumbing and allows the user to authenticate through any of your subdomains.

How Does it Work?

I. Initial Authentication

Firebase Auth Step 1

  1. First the user authenticates using Firebase Auth to obtain an ID Token on the client side on any subdomain. For this example the user authenticates through app1.domain.com.

  2. The user then sends that ID Token via POST to the Cloud Functions endpoint /auth/login on the same subdomain, app1.domain.com.

  3. The Firebase Hosted website rewrites /auth to the AuthFunction Cloud Function.

  4. AuthFunction takes the ID token, verifies it using verifyIdToken() and then calls createSessionCookie() and assigns that value to the __session cookie with the domain .domain.com giving it access to all of the subdomains of the requesting domain. The cookie should have httpOnly=true, secure=true and sameSite=strict set.

Note: __session is the only cookie name that Firebase Hosting allows you to use. Any other cookies get stripped. Source

II. Cross-Domain Authentication

Firebase Auth Cross-Domain Authentication

  1. Assume the user is now authenticated on app1.domain.com but we need the user to be authenticated on app2.domain.com. First the user checks if it's authenticated with Firebase Auth client side, then it makes a GET request to https://app2.domain.com/auth/status.

  2. The Firebase Hosted website rewrites /auth to the communal AuthFunction Cloud Function.

  3. The /auth/status endpoint checks for the existence of the __session cookie, then validates the session cookie value with verifySessionCookie(). If valid it calls createCustomToken(<uid>) and returns the custom token to the client. If not it returns a 401 error and clears the __session cookie.

  4. If a 200 status code is returned, the client takes the custom token and calls Firebase's signInWithCustomToken() passing the custom token. Now the user is authenticated on app2.domain.com.
    If a 401 status code is returned, the client logs out through Firebase Auth and is sent to the login page.

Destroying a Session

Finally when a user logs out, the /auth/logout endpoint should be called to perform two actions:

  1. Clear the __session coookie.

  2. Optionally call revokeRefreshTokens(<uid>) to revoke all tokens for that user across all devices. Otherwise if you want to revoke authentication on a single device you'll need to monitor for the presence of the __session cookie and if it vanishes the user should be logged out using Firebase Auth. The latter requires that the cookie's httpOnly property is set to false.


To be continued with code examples.

Discussion (7)

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 Author • 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 Author • 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
kevinmmansour profile image
Kevin M. Mansour

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