Role Based Redirects causing an infinite loop

Currently have a role-based redirect on my deployed site to gate content and redirect visitors to the login page. Unfortunately, I’m unable to share the project but I will show the redirect rules and functions I have applied on the instance -
_redirects:

# Always allow
/login    /login    200
/docs/icons/hero.svg    /docs/icons/hero.svg    200
/templates/*    /templates/*    200
# If a `basic-user` serve page
/*    200!   Role=authorized
# Other send to login
/*    /login    302!

scripts used in login.html:

<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
<script>
const user = netlifyIdentity.currentUser();
// Bind to login event
netlifyIdentity.on('login', user => location.href = '/');
</script>

I also have a working serverless function identity-signup to automatically assign roles on user sign ups.

Problem is that when I access this instance with the cli tool with command ntl dev, it opens up the /login page just fine, but when I login it does not redirect me to /, but rather, loops with the 302 redirect code between /login and /.

A similar issue happened to my colleague but this was happening on the deployed instance. It starts with him signing up through an email invite and logging in, and testing it out again with another email address and signing up with that within the same browser that the first account had logged in, causing the same looping redirect that’s not stopping.

I was wondering if this has anything to do with the JWT being mangled between the 2 emails he has, and if it’s a similar issue happening within the local instance and the deployed instance?

Hi @NikShafiq

I believe this issue is related

Also, is this related:

Thanks guys, had a read through those topics and I believe it could be something else.

Problem was that the JWT has an expiry date within 1 hour after creation, and my /login page has a redirect to / with netlifyIdentity.on('login', user => location.href = '/');.

Problem comes when the token expires but a user is still logged in, when doing a browser refresh, the role-based redirect kicks in and tries to push the user to /login but Identity still thinks the user is logged in (the login button is displaying logout), so it pushes the user to / with the redirect script above, this causes the browser to constantly have a redirect loop until you stop the reload and log out.

I had to fix this by making a JS to refresh the user token after it expires without having the user relog in. There seems to be a bug within Identity and it shows the user’s token is expiring in 1 day rather than 1 hour, but the token will still expire within 1 hour nonetheless.

Hope this helps anyone out there who will face this issue

This (which I believe was something I mentioned in another thread of yours @NikShafiq) was never a you just need to do this kind of thing, rather a very basic demonstration of a redirect on login.

If a user landed on a specific page (e.g. /docs/private/page/here) that was a gated page, the user might expect to return to that page once they successfully logged in rather than the homepage—they would then need to navigate back to the page they wanted. This is the sort of logic you might handle in the on('login') event trigger.

Same would go for checking the cookie/token expiry on the first page load.

Also, the Identity Widget automatically handles the token refresh and you need not do it yourself.

This is how GoTrueJS works:

  1. User send a login request.
  2. GoTrue validates the credentials, triggers your webhook and that sends the GoTrue user object as the response body along with a cookie named nf_jwt and the value as the JWT token for the generated user object.
  3. The identity widget stores the user object in browser’s local storage with the key gotrue.user.
  4. On subsequent page loads, the Identity widget checks the token’s expiry, send a request to fetch the updated token, receives the new cookie along with the new refresh token which is again stored in the local storage.

All of this is supposed to work automatically, which is why we recommend using the widget. You can skip using it or even skip GoTrueJS and use something like Axios or Fetch to do all this (like I did just to experiment once), but then you need to handle all this by yourself.

1 Like

Hi @hrishikesh,
Coming back to this issue after some time. How would the Identity Widget handle the refresh itself? With my previous solution that involved redirecting based off roles and after login, causing the loop when token is not refreshed, would that have caused the automatic refresh to be interrupted due to the infinite loops?

@coelmay after some time I’m realizing what you mean now with the demonstration of redirect after login. But now I’m having the issue of users being lead back to home page after token refresh rather than the specific page they were linked to. I was wondering what would be the solution then to lead the user back to the specific page once they’ve logged in. Would it be a basic window.history.go(-1); or is it something else?

Hi @NikShafiq

The Identity Widget refreshes the token by making a request to an entity endpoint, like this:

Then it evaluates the need to refresh the token and it either refreshes or it doesn’t.

With my previous solution that involved redirecting based off roles and after login, causing the loop when token is not refreshed, would that have caused the automatic refresh to be interrupted due to the infinite loops?

Hard to tell, but you can check this on your end I believe. If you navigate to the page where the redirects are happening, can you look to see if the request is there with a 200 response? To see this, you need to:

  • open up the Dev tools and preserve logs:

  • check to see if the request exists on the left section where all the requests are listed. Feel free to filter for Fetch/XHR

If the request has a 200 response it means it checked successfully.

Regarding the second question, this depends on whether you’re using a framework such as React (which has its own router) or plain JavaScript. If you’re using the latter you could use something like:

location.reload()

Let me know if this helps!

Thanks for your reply @gualter, I’ve submitted another post regarding the second question and found the solution to be the same as yours, location.reload(). Regarding the first question, I can see token request is being done with status code 200 when logging in. I then deleted the nf_jwt token in cookies and did a refresh and did not see any more token request being sent. I’m assuming this is the cause as to why my session’s token is not being refreshed causing the infinite loop?

For context, most of my pages have the netlify-identity-widget script, and due to this issue (that I’ve faced months ago), we’ve implemented a token refresh code on our own. We’d like to get rid of our token refresh if Netlify’s Identity Widget can in fact refresh on its own without redirecting anywhere, but until then I guess we’ll be refreshing the token ourselves.

Hey there, thanks for your patience!

In order for us to continue debugging this further, we will need a login instance. Would you be able to create one for the Support team? Thanks!