16

I use firebase for authentication on my website and I want to keep the users auth session active across subdomains.

Unfortunately, firebase uses Local Storage to store the user's session. Which unfortunately is independent to each subdomain.

I already know that you can generate a JWT token using firebase from the server side, but then it doesn't allow the user to log out of the site because the user would still end up logged in other subdomains.

geooot
  • 338
  • 3
  • 9

5 Answers5

18

After having spent much longer then I intended to getting single-sign-in working across subdomains, I wrote up a blog post detailing how to accomplish this.

As a high level overview (which ignores the important security details):

  1. We have three applications at different domains.

    • accounts.domain.com
    • app1.domain.com
    • app2.domain.com
  2. We have three Firebase Functions

    • ...cloudfunctions.net/users-signin
    • ...cloudfunctions.net/users-checkAuthStatus
    • ...cloudfunctions.net/users-signout

In order to sign in:

  1. Someone navigates to the accounts.domain.com app
  2. They provide their authentication information
  3. That authentication information is sent to our /users-signin cloud function which verifies the information and, if valid, sets a signed __session cookie which contains the user's UID and returns a success indication to the client.
  4. On success, the client calls the /users-checkAuthStatus cloud function which looks for the signed __session cookie, extracts the user UID, and uses the UID and the firebase-admin SDK to mint a custom auth token which it returns to the client.
  5. When the client receives this custom auth token, it uses it to sign in using the firebase javascript SDK.
  6. When someone navigates to one of the other apps, say app1.domain.com, the app first checks to see if the person is already signed in using the firebase javascript SDK.
    1. If they are, awesome.
    2. If not, it calls the /users-checkAuthStatus cloud function which looks for the signed __session cookie and returns a custom auth token to the client if a valid __session cookie is found.
      • If a custom auth token is returned, the client uses it to sign the user in using the firebase sdk.
      • If a custom auth token is not returned, it means the user isn't authenticated. You can then optionally redirect them to the authentication app to sign in.

Again, this is a high level overview which ignores issues like cross-site-scripting attacks, actually signing out, etc. For more information, check out the blog post.

John
  • 9,249
  • 5
  • 44
  • 76
  • Can you take a look at my question ? I cant get it solved for several days now https://stackoverflow.com/questions/63424850/firebase-function-session-cookie-is-not-defined-on-subdomain – niclas_4 Aug 16 '20 at 10:24
  • Thanks for the guide. Is there any way that this can be accomplished over different domains like domain1.com and domain2.com or does it only work for subdomains? – Holger Sindbaek Jun 28 '22 at 14:10
8

this is correct. Firebase only supports single host origin sessions. Firebase Auth is looking into supporting cookies. For now there is no easy solution for this. Feel free to request this feature at the Firebase forum: https://groups.google.com/forum/#!forum/firebase-talk

For now, if you really need this, here is one relatively easy option: Create an endpoint that takes a Firebase ID token and basically returns a custom token for its underlying user (you would need to use the Admin SDK to do this, you verify then ID token, get the user UID and then mint a custom token). The subdomain where the user signed in would pass the ID token to the other subdomain where the user is still not authenticated (you can use iframe cross origin postMessage to pass it, or just save that ID token in a *.domain.com policy). The custom token can then be used to signInWithCustomToken with the custom token, effectively signing in the same user on this page.

This is risky though as the endpoint could expose a vulnerability (it transforms a short lived token to an indefinite one). If the ID token is leaked, an attacker can basically sign-in as the user exploiting this endpoint.

bojeil
  • 29,642
  • 4
  • 69
  • 76
  • Thank you for this answer. Do you have any suggestions for mitigating that risk? I was under the impression that the custom token expires in an hour anyway, so it's still short lived. – chez.mosey Mar 08 '18 at 12:33
  • The problem is anyone who gets hold of an ID token can transform it to an indefinite session via the custom token endpoint you create. To mitigate, check `auth_time` in ID token to ensure the user was recently signed in. This narrows the window of attack. – bojeil Mar 08 '18 at 18:17
  • Another question. Passing the ID token via postMessage seems a pretty insecure, as any content script from another extension can listen to the message. So, the concern that the ID token could be leaked has high potential, given that you're not JUST sending it back to the other subdomain, your posting it for all content scripts to see. Am I missing something, or is this also a security risk that needs to be considered. – chez.mosey Mar 12 '18 at 15:30
  • What do you mean? you are postMessaging back to a domain you own and trust. If there are malicious scripts on a domain you own then you have worse problems to worry about. – bojeil Mar 12 '18 at 16:44
  • If the user has downloaded a malicious chrome extension, that has a content script that runs on all tabs that are open, then the content script could easily read/intercept messages passed between subdomains, even if those subdomains trust each other. If I understand correctly, a content script receives all messages that are sent to the parent web page. So, I can trust the subdomain, but I can't trust the chrome extensions that my user has installed. Although maybe I don't understand the security of chrome extension content scripts well enough. – chez.mosey Mar 12 '18 at 18:38
  • If you are worried about chrome extensions reading site content, then you should worry about other content on your site being read. You basically can't do anything security sensitive. `postMessage` is a well established technique for passing cross origin data securely. This does not add any additional security risks to your site that do not already exist. If you don't want to use it then that is fine but there is no fact in your claim that this is insecure. – bojeil Mar 13 '18 at 01:50
  • Just want to add that abusive chrome extension risk is a problem for many websites. There is little sites can do to guard against them (you could show a warning or some educational information). The responsibility falls on the user to avoid installing shady chrome extensions. – bojeil Mar 13 '18 at 01:53
  • 1
    How about using a very short-lived session cookie on the login domain instead of using postMessage, and then the login domain will accept a GET request for a custom token matching the session cookie? The GET request can enforce a CORS policy for trusted domains. The benefit of this approach is that login can occur by redirect instead of as a pop-up or iframe. – jacob Dec 20 '18 at 20:58
  • Hey @bojeil, I am trying your suggestion. Now I can get the token from the server and pass it to the client side. But what do you mean by saving that ID token in a *.domain.com policy? How can I achieve this? Thanks! – damingzi Jun 27 '20 at 05:14
4

The iframe doesn't work anymore for Safari because it doesn't let the iframe's origin page access its own indexeddb anymore. That means you cannot get the id token and onAuthStateChanged will always return null.

We've implemented another solution where we store a custom token into a secure cookie along with a redirect information, redirect the user to the other domain, use the cookie to sign in or sign out the user, delete the cookie and redirect him again to the location stored in the cookie.

  1. Login
  2. Get custom token
  3. Set cookie with action "signIn" or "signOut", redirectUrl and token (if signIn)
  4. Redirect to other page
  5. Sign in or sign out
  6. Delete cookie
  7. Redirect to redirectUrl

That works for iOS and Desktop Safari again. But it only works if it's on the same domain so that both subdomains are going to have access to that cookie.

Gambo
  • 4,790
  • 2
  • 14
  • 14
3

It appears Firebase now has support for cookies built in so you should be able to follow this new guide to use it across subdomains:

https://firebase.google.com/docs/auth/admin/manage-cookies

Travis Reeder
  • 38,611
  • 12
  • 87
  • 87
0

I used NGINX to load diffrent web apps which want to share same firebase auth which works out of box in firebase if domain or sub domain is same.

server {
root /var/lib/jenkins/workspace/app/dist;
index index.html index.htm index.nginx-debian.html;
server_name app.com; # example

location /app1 {
        alias /var/lib/jenkins/workspace/app1/dist;
        try_files $uri $uri/ =404;
}

location /app2 {
        alias /var/lib/jenkins/workspace/app2;
        try_files $uri $uri/ =404;
} 

location /static {
        alias /var/lib/jenkins/workspace/build/static;
        try_files $uri $uri/ =404;
}

location ~ /\.ht {
    deny all;
}

listen 80;
listen [::]:80; 

}
Kathan Shah
  • 1,655
  • 17
  • 25
  • Kathan Shah, could you please explain how it works? I am having something like auth.example.com, dashboard.example.com and services.example.com. I want to have single authentication in auth.example.com, so other two services can auto login. – Nithya Rajan Apr 29 '23 at 12:03