This post is intended for people who are already familiar with Firebase, Firebase Authentication, and who are using Firebase in their web apps.
If...
For further actions, you may consider blocking this person and/or reporting abuse
Thanks for this article! Is it possible for Firebase Auth to support any sub-domain? I mean, when you don't know the sub domain ahead of time?
Say you allow users to have unique urls for their profile:
user1.subdomain.com
user2.subdomain.com
I'm not sure. I haven't had to deal with subdomain authentication in firebase for a while now (I'm no longer working on the app that sparked this article).
Thank you for pointing me in the right direction with this post. I came up with a simpler approach that doesn't require
csst
cookies, let me know what you think:dev.to/brianburton/cross-domain-fi...
Happy you've found this post helpful! I added a comment to your article but I'll repeat it here:
I like the general idea behind your approach, 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?See this discussion which I had with another user who proposed using
revokeRefreshTokens()
.FYI, I added a link to your article to the bottom of mine.
Do you know if the following would work?
1) In the auth.domain.com app, authenticate the user and get a token
2) redirect the user to app.domain.com with a parameter that is set to be the token
3) check the token provided by extending the Function service from auth.domain.com project to app.domain.com
4) if valid perform new authentication from app.domain.com and issue new token to user (I guess this would not allow users to have multiple clients openned and working at the same time -- does the shared cookie solves this issue?)
My guess is no. For one, it sounds like someone would need to re-login each time they navigated to a new subdomain.
That's correct.
To circumvent setting a cookie in Functions and the problem of passing them through to the client, couldn't we just pass the cookie ID in the response, and set it at client level? Am I missing a security issue? That would relive me of a big pain...
Well the entire purpose of this post is to share sign in status between subdomains, and you’re not doing that (in your proposal at least).
Maybe I am misunderstanding something here or badly expressing myself..
What I am doing atm:
1) Sign-in and get token ID from the client
2) send the token ID to functions, validate token ID, generate session cookie and a jwt token in Functions, return the two values to the client
3) in the client set the two cookies for domain *.domain.com
4) all cookies are available accross all subdomains (tested), so I can perform the authchecks required
Something I am missing?
That sounds good. Sounds like the same thing this blog post suggests. Honestly though, I'm no security expert. I'm confident enough that following the steps in this post will work and is secure (after having spent a while researching it), but I have no advice if you are looking to do some variation of this.
This post is really just a summary of my findings after spending a week working on this problem. Beyond what's here though, you're on your own.
Fantastic documentation of the flow, got pretty much the entire flow implemented except for the mentioned monitoring of the
csst
cookie. All implementations of any sort ofcookie
"event listeners" I find have somesetInterval
hackiness going on, so I'm curious if you have any pointer as to how you'd monitor the presence of the cookie?Cheers, again!
Sorry, I missed this comment when you originally made it. I also monitor the presence of the cookie using
setInterval
(I don't think there's any other way to do it). Specifically, I use theinterval()
observable creation function from rxjs.Thanks. I've been looking for examples that do exactly this!
One question though, for signout, what about just revoking the refresh token? That should log the user out everywhere.
I've been there 👍.
"Logging the user out everywhere" sounds like a solution specific to your app. In general, users don't want to log out everywhere. They just want to log out of that browser.
Good point. Revoking the refresh is quite drastic.
I love the explanation, and yeah there really isn't any documentation to this at all. It's frustrating.
The only thing that would have made this post better is to showcase some of the code involved to get a better grasp of how this can be done.
I have evaluated Google Identity Platform /Amazon Cognito and Azure B2C. This approach is work but as far as I understood should not be used because it is not secure. Google Identify Platform (Firebase Authentication) does not support multidomain.
Usually we need to sign in by a single credential across all subdomains but it doesn't mean we can use the same access token! It sounds that this approach uses a single access token for all subdomains which is not secure why?
Imagine you have an admin panel and a simple game in your organization such as admin.domain.com and funnygame.domain.com. In this scenario you are giving the admin access to the funny game team because they can use that token to access admin portal. access tokens must have separate audience or scope for each individual subdomain.
Hi Mohammad,
You seem to be conflating authentication, which this article discusses, with authorization, which this article does not discuss.
Authentication is the process of determining who someone is. This article helps you do this across subdomains in a secure way.
Authorization is the process of determining if a known or unknown client has access to something. This article does not help you with this. Just because you've authenticated someone and know who they are on every subdomain, does not mean you need to give them access to all (or any) data on each subdomain. You said, "Imagine you have an admin panel and a simple game in your organization such as admin.domain.com and funnygame.domain.com. In this scenario you are giving the admin access to the funny game team because they can use that token to access admin portal." But this is only true if you don't implement authorization. For example, you can (and probably should!) have different Firestore security rules for
admin.domain.com
andfunnygame.domain.com
.If you're not sure how to authorize users within Firebase, you'll need to learn how to do that by reading the Firebase documentation or other articles on the internet. That's out of scope for this article.
Also FYI, this is incorrect:
The approach discussed here results in the user having a different Firebase auth token for each subdomain. This is necessary because Firebase Authentication (again, authentication not authorization) doesn't support single sign-in across subdomains. From the article:
I'll also point out that having a single authentication token shared between subdomains is not inherently insecure (but obviously it could be depending on the authorization strategy).
PS: I'll reiterate the very first sentence of this article
Dear John,
Thank you for your complete answer.
I completely understand the difference between authorization and authentication. Still, it is impossible to authorize an authenticated user if you don't have enough information in its id-token or access token.
Yes, Anyone who needs to find the proper tools looks for some key points and possibilities before implementing the whole system. Indeed, Your article works if there is something in authentication tokens so the access-token function can distinguish the domain. However, it sounds like it needs a lot of customization to achieve this, especially when I compare it with AWS Cognito. It would be so helpful if you put a sample of authenticated tokens (JWT) in each step of your article.
To sign-in:
Here there is no trace of the audience domain, and I couldn't understand how "/users-checkAuthStatus cloud function" can generate the token and validate the authenticity of the requested subdomain.
Perhaps I need to learn much more and implement it to understand.
Thank you for your helpful post.
But I don't understand why we need Firebase functions here.
I means why we don't create corresponding endpoints on the accounts.domain.com itself like this:
Could you please explain more on this?
My approach uses Firebase functions to accomplish the goal. I imagine there are other ways of accomplishing the goal as well.
I've been stuck on this for like a week and I'm hoping you can help. What is the link between firebase's session variables and the front end? I use response.set to set the session cookie, but then when I call another cloud function, request.cookies is null. Am I supposed to store firebase's session variable locally and then pass it back to the cloud or something? If so, any advice on where I can figure that out (I've been searching through EVERYTHING on Google and I'm desperate haha.) As a workaround I thought about storing the uid in a cookie and then minting a login token across subdomains but this is obviously a major security risk because someone could hack in another uid and get access to their account without their credentials.
Here is my sign in server code:
corsMiddleware(request, response, () => {
console.log(request.body);
//admin.auth().
const idToken = request.body.idToken;
const expiresIn = 60 * 60 * 24 * 5 * 1000;
admin.auth().createSessionCookie(idToken, {expiresIn})
.then((sessionCookie) => {
// Set cookie policy for session cookie.
const options = {maxAge: expiresIn, httpOnly: false, secure: false};
response.cookie('__session', sessionCookie, options);
console.log(sessionCookie);
response.end(JSON.stringify({status: 'success'}));
//return response;
}).catch(error=>{
response.status(401).send('UNAUTHORIZED REQUEST!');
Here is my checkSessionCookie server function:
const sessionCookie = request.cookies.__session || '';
// Verify the session cookie. In this case an additional check is added to detect
// if the user's Firebase session was revoked, user deleted/disabled, etc.
admin.auth().verifySessionCookie(
sessionCookie, true /** checkRevoked */)
.then((decodedClaims) => {
console.log("Got cookie");
console.log(decodedClaims);
//serveContentForUser('/profile', request, response, decodedClaims);
})
.catch(error => {
console.log("No cookie");
// Session cookie is unavailable or invalid. Force user to login.
//res.redirect('/login');
});
Sorry, I've never used the
admin.auth().createSessionCookie()
method and I'm not familiar with it.Hi John
Could you please share how you have implemented firebase auth credentials check in users-signin function?
Did you use frontend SDK and passed uid to backend?
Or just using npm firebase module?
If the second I wonder if it is the right way?
Please see stackoverflow.com/questions/503709...
Thanks
I'm not 100% sure I know what you are asking, but I handled signin this way:
This being said, when I set things up I didn't realize (until later) that the firebase sdk's IdToken contained the provider which issued the token (which is important to prevent someone from using a custom ID token to authenticate again and again). Since it does, I'd probably use this method if I were doing things over again:
Immensely useful to get strated in teh right direction, thanks!
Thank you for this article!
Do i need to host all my apps in firebase hosting so that the functions can set the cookie for my app domain ?
I'm not sure, I haven't had to think about this for a long time now.
Hey, thanks for replying
please can you just take a look, i ve been stuck in this task for couple of week and i can't find clear insight
I have to make the decision to change the hosting to firebase of all my sub apps if it is necessery for the fuction to be able to set the cookie in my domain
Did you use firebase hosting to host all the apps of subdomains ?
I did.
I mean, you can read the Firebase docs and do research on the internet as well as I can.
i read the docs and everything, i hosted my apps in firebase hosting, still the cookie __session is not set in the browser,
i can see the request containing the cookie but not setting it in the browser
please one last question: when you call your cloud function ...cloudfunctions.net/users-signin which generate the cookie ..., do you call it using the google domain url or the custom domain url ?
In order for the cookie to be set, the function will need to be on the same domain as the client app.
Also, if I remember correctly one of the links in this post directs to a Google Chrome issue where it didn’t show the cookie being set in the browser. Not sure if it’s the same as what you’re experiencing though.
Can you share more details about csst token? If user inactive for a long time, this JWT maybe expired. How can they get sign-in?
Cross site scripting tokens are a standard feature of most websites. You'll need to find another tutorial on the internet to learn how to set them up if you're looking more detail than this overview has. I don't think there's anything special about them in this case.
If, as suggested in the post, you monitor the csst to see if the user is signed in or not
Then when the csst token expires the person would automatically be logged out of firebase and you could redirect them to a login page.
Hello. Please could you follow this up with some working code example.
No, sorry.