my frontend keeps attempting to refresh even though i just logged in
c
my frontend keeps attempting to refresh even though i just logged in
Any idea why?
logs
Seems like the cookies are not sent to the backend
r
Hmm. I think you need to enable sharing of cookies across your api domain and website domain
There should be a config on the frontend called cookieDomain and backend called cookie_domain (in session.init)
Set its value to “.placeholder.info”
This way cookies will be sent to your next server as well as well as to your api domain
c
I tried that but I have two front ends using Supertokens for auth
If I do that, it works. Except that when I login/logout on one site, the other gets affected too
r
Can you elaborate and provide domain names?
c
Yes
So two front ends:
1. www.placeholder.info
2. admin.placeholder.info
Backend
1. api.placeholder.info
Both front ends use the same api
If I have cookieDomain=“.placeholder.info”, when I login to www.placeholder.info, admin.placeholder.info sees that login too
Same thing for logging out
Reason is because they share the domain .placeholder.info
Both front ends see the same access and refresh tokens
r
Ah yes.
Well, since they both hit the same api endpoint, this problem do the session being shared will happen even if you do not set that cookieDomain config. Is that not happening?
c
If I set the cookieDomain, the aforementioned problem occurs
If I don’t set cookieDomain, infinite refresh occurs
I clearly see the cookies in the browser’s application tab. But for some reason it keeps refreshing
r
So you could, set that cookieDomain config, and also set in the access token payload on the backend the domain it’s meant for
c
The cookies have the domain “api.placeholder.info” when I do not set cookiedomain
Not sure what you mean
r
And then in admin site, do session verification, but then also check that the domain it’s meant for is the admin one
c
Im just a little confused, why is it doing an infinite refresh?
r
I mean override the create_new_session function on the backend and in the access token payload, set a custom key value like “forDomain: admin” or “forDomain: non-admin”
c
It’s not supposed to do that I think. The cookies have the domain “api.placeholder.info” so it should be sent to the backend no problem, except it’s not?
r
It’s doing an infinite refresh cause maybe ur trying to do session verification in getServerSideProps?
c
I see
This is true
r
Yea. So that’s failing cause the cookies are not being sent.
c
Why is it failing?
It works locally, only fails in prod
r
Cause the cookies are not sent. Cause they are attached to the api domain and not the www sub domain
c
I’m extracting the cookies from context, then sending them to the server
`export async function getServerSideProps(context) { let cookieString = ''; for (var key of Object.keys(context.req.cookies)) { cookieString += key + '=' + context.req.cookies[key] + '; '; } try { let myAxios = await myAxiosPrivate(); var res = await myAxios .get(
/users/me
, { headers: { Cookie: cookieString, }, }) .catch((e) => { return e.response; }); if (res.status === 401) { return { props: { fromSupertokens: 'needs-refresh' } }; } return { props: { _res: { data: res.data, status: res.status }, }, }; } catch (error) { console.log(error); } } `
r
Yea but for that the cookies need to be sent to it by the browser
c
So the problem is this function is unable to send the cookies to api.placeholder.info, right?
r
No. The problem is that the browser is not sending cookies to the next server (which runs the getServerSideProps function) cause the cookies are only attached to the api domain, and not the www domain. Setting cookieDomain=.placeholder.info attaches it to both (and admin unfortunately)
c
Ah I see
Damn
r
Well, on the admin site, you should anyway have checks for if the userId from the session is an admin or not
c
I do
r
And if you have that, even if cookies from the other site are sent to the admin site, it won’t work
As in it will yield with an error state. Which I think is fine
So I think you should add that setting
Or else you will have to give up on server side rendering session verification.
c
So right now I have protection for my API
it checks if the user role is "admin"
r
Right
c
So no problem there
On the admin site
I use SessionAuth for route protection
Copy code
useEffect(() => {
    const abortControllerRefCurrent = abortControllerRef.current;
    const wrapper = async () => {
      let res = await getCurrentUser(abortControllerRefCurrent);
      if (res?.status !== 200 || res?.data.role !== 'admin') {
        await signOut();
        window.location.reload();
      }
      setLoading(false);
    };
    wrapper();
    return () => {
      abortControllerRefCurrent.abort();
    };
  }, []);

  if (loading) {
    return (
      <div className="flex h-screen">
        <div className="m-auto">
          Loading
          <Spinner size={10} />
        </div>
      </div>
    );
  }
r
That runs on the client side. And you can add checks to that to make sure it’s an admin
c
So I am doing that
If the user role is not "admin", they will be logged out
There are two problems here
r
Don’t log them out. Display an error saying unauthorised.
c
1. If I log into the admin site first, and then open www.placeholder.info, I am already logged in
r
Well yea, on the other site check that it’s not an admin
c
2. If I login to www.placeholder.info first, depending if I am "admin" or not, I might be logged out
r
Ok. Let’s say that you do logout the user
Is there a real issue in that though? Cause actual users won’t be switching around these sites anyway
c
That differs for people I guess
r
Hmmm
c
I'm just curious what the actual solution is
Another weird issue
r
Well, unfortunately there isn’t a perfect solution to this. Cause the browser doesn’t allow you to specifiy exact list of domains for cookieDomain
c
I am logged in to the admin site, and go to www.placeholder.info, it shows that I am not logged in
Although the access and refresh tokens with the domain "placeholder.info" are there
r
Yea to solve that, you need to set sessionScope config on the frontend’s session.init to .placeholder.info
c
But why doesnt the opposite happen?
If I am logged into www.placeholder.info, and go to the admin site, I am logged in
r
Does it do a refresh when you go to the admin site when u first login to www?
c
Nevermind
r
The good solution to this is to just add proper access control to each site and check for that post session verification. That should be good enough. Or else, disable server side rendering session verification
c
Let me clarify that
So
If I am logged into www.placeholder.info, and then I log in again on the admin site, the logged in user on www.placeholder.info changes
changes to the admin user
r
Yea. That’s expected.
Cause u logged into the admin site
c
ok makes sense
r
And sessions are shared
c
yeap
How should I do a proper access control
r
Well.. in admin site check for admin role everywhere post session verification
In non admin site, check for regular role everywhere post session verification
If the roles don’t match up, display an error message.
That’s all
Or redirect the user to the right site
c
hmm that would require a check on every page right?
and every action (like clicking a button on the admin site)
r
Yea. But that you can do by adding the appropriate session claim validator to the global validator claim list on the frontend and backend
So whenever u use verifySession or getSession function, it will check for that automatically
Oh wait. Wrong link
Let me send u a code snippet of it since I don’t think this is documented
c
Ok thanks
r
So this goes on the frontend on the admin site in session.init:
Copy code
tsx
Session.init({
    override: {
        functions: (oI) => {
            return {
                ...oI,
                getGlobalClaimValidators: function (input) {
                    return [...input.claimValidatorsAddedByOtherRecipes, UserRoleClaim.validators.includes("admin")]
                }
            }
        }
    }
})
We are making sure that each use of SessionAuth checks that the user roles includes the admin role
This goes on the frontend for the www site:
Copy code
Session.init({
    override: {
        functions: (oI) => {
            return {
                ...oI,
                getGlobalClaimValidators: function (input) {
                    return [...input.claimValidatorsAddedByOtherRecipes, UserRoleClaim.validators.excludes("admin")]
                }
            }
        }
    }
})
here we make sure that the roles list doesn't have admin role
c
Ok thanks for your help, I appreciate it
It's a weird problem 🥲
r
and in the getServerSideProps functions, i guess you don't need to make any changes? Cause the APIs it queries anyway has the right access control check right?
c
Yeap
Thank you
r
Happy to help 🙂
Oh. And I forgot to say. If the above role validators fail, SessionAuth will still show the children content, it’s on you to check the failed validators in the children component and render an appropriate error message
You can do that as shown in the link I had sent previously (see the protecting website route section)
It wraps SessionAuth with a component that renders an error message in case the role validator fails. You need to make something like that
c
Can you keep this thread open? I will need to come back and read this again some time in the future
r
You can save a link to this thread. It will auto archive, but it won’t delete
c
I see, thanks!
37 Views