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 -

# 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=""></script>
const user = netlifyIdentity.currentUser();
// Bind to login event
netlifyIdentity.on('login', user => location.href = '/');

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