Problems with Redirect JWT role-gated pages on edge

  1. The documentation inconcistently indicates in some places that redirection based Role gating is a Business team teir only feature. However I find it works on the following site.
(AKA )

That’s great as I need it for my charity project. I hope it should work as I see this a basic requirement of Jamstack - otherwise you need a function to gate content on demand - not very Jamstack at all, and definitely not on the edge! :frowning:

  1. The documentation gives examples with a _redirects file but not using the netlify.toml. I have not found the right syntax that works in the toml. The key problem is you do not need a to: path for the role gating but one is required by the syntax

  2. Most anoyingly it does not work with the awesome “netlify dev”. If I have no _redirects file then all is well but as soon as i add one with this rule

/rdm/* 200! Role=admin

then the /rdm/ page cannot be reached - whatever the role when logged in. The tab just endlessly shows a spinner (Firefox).


The hanging may be the “!” in the redirect as when I have “force=true” in the toml I get the same effect. I’m guess the two do the same thing?

Hi @slim, do you have a fallback redirect rule after that Role-based one? It will likely remain in that loading state due to the request being rejected with a 401 but there is no fallback redirect rule so it’s got nowhere to go. Likely if you add the following, things would work:

/rdm/* / 401!

Let me know if that works for you.

1 Like

Thanks Dennis

I’ll give that a go but would much rather the the same behaviour as the deployed site - ie 404 if not the right user or else letting access the page.

As of right now I don’t have a good conceptual model for how the redirect rules work. Some doc would help. Perhaps just the algorythm used?

Sadly not. If I do not have he role (eg not logged in) it just spins.

I’m assuming the Netlify Dev must “phone home” to check the user roles so is that what is not working? Mind you what if i’m not logged in?

my mistake - the 401 redirect is working locally. I need

/rdm/* /404.html 401!

though for my custom 404 page, so is the netlify dev not performing the same auto 404 routing that the edge does? Could it for consistency?

Sadly though I’m still not getting access when I am logged in as a user with the rdm role :frowning:

Hey @slim,
Here’s an example of a netlify.toml for the kind of use case you’re talking about:

# access auth page regardless of whether you're authenticated
	from = "/auth.html"
	to = "/auth.html"
	status = 200

# if authenticated, access 404 page
	from = "/*"
	to = "/404.html"
	status = 404
	conditions = {Role = ["admin"]}

# if authenticated, access everything
	from = "/*"
	status = 200
	force = true
	conditions = {Role = ["admin"]}

# for everything else, you're pushed to the auth page with 401
	from = "/*"
	to = "/auth.html"
	status = 401
	force = true

Our toml and redirect files are parsed and applied top to bottom, so the final rule acts as a catch-all when the first three rules don’t apply. The number of rules needed can be a bit confusing, so wanted to share in case this is helpful.

Greetings, can someone verify or refute @slim’s statement:

  1. The documentation inconsistently indicates in some places that redirection based Role gating is a Business team tier only feature. However I find it works on the following site.

From the forums and docs and pricing plans that I reviewed, it does seem that 3rd Party (External providers) JWT tokens containing a nf_jwt to define redirects by roles in netlify.toml will only work with the Business plan.

Perhaps it used to work on Pro plan, perhaps the Business plan only is a new change?

In a past blog: “If you aren’t already on a Teams Plan, sign up today to get access to this incredibly powerful feature!If you aren’t already on a Teams Plan, sign up today to get access to this incredibly powerful feature!”

Role-based redirects in docs
Page links to the plans which shows Visitor access control (JWT auth) as only available in Business:

Please clarify so I can understand which plan I will need to start auth development on Netlify.

Thank you

@jen @Dennis in this thread


Hey @i_a,
Using Netlify Identity to gate pages based on role is available at every plan level, including the Starter level. Using third-party authentication (like Okta) to gate pages is only available at the Business plan level or above. Let us know if that answers your question or if there’s anything else we can help with.

@jen Thanks for your reply.

So External provider JWT is only available on Business Plan. Thank you for clarifying.

So to summarize, to truly protect routes via server-side redirects, either Identity or Business Plan is required. (Because front-end SPA routers are not actually secure).

Other than using Netlify Identity or selecting the Business Plan, there is no gated user authorization / secure area for a Netlify hosted JamStack site.

Thank you

Hey @i_a :wave:t2:

That is true, but do understand that Netlify Identity is itself a secure Auth provider (like Okta, Auth0, etc.) and has deep integration with Netlify’s Redirects engine and Netlify Functions (which are super powerful when combined with Identity).

That’s exactly what Netlify Identity was built to do. I’m not sure why you would phrase your statement in that way: “Other than by using the thing made to accomplish the task, we can’t accomplish the task” …well, yes.


@jonsully Thanks for your question.

We’ll if you’re developing / experimenting with an Auth system using JWT, starting out / testing at $99/month is not going to cut it.

And if you use Identity, you’re not going to be able to use JWTs.

And if you just use Identity overall, after the first 1,000 you’re pretty much locked in at $99/month. Hopefully those first 1,000 users would be paying $10/month sooner than later.

So there’s lots of pressure to create an early price-module for userland, versus creating a cool service for userland that can just gain traction slowly over time.

I’m still confused here. Identity is built on JWTs… and free to use, including Netlify’s deeply-integrated visitor access control, for up to a thousand users. It’s a great bootstrapping value proposition.


Let me clarify:

It’s a great proposition, but it also could get you locked-in. Not sure what would happen if at 1,000 users or whenever, you would like to switch to a different JWT Auth system.

Well migrating from one auth provider to another is always a tricky task… that’s a fairly large piece of architecture to swap. That said, you can migrate off of Netlify identity if you’d like to or need to. A bit of an older thread and doesn’t give all the details per se (I can if you need)…

But the point is that Identity’s API absolutely offers endpoint access to your full instance data that you could use to migrate / hydrate a different provider’s user DB with. Your users would obviously need to reset their passwords since you can’t export password data (for good reason), but I don’t think there’s a “locked in” vibe here. Nothing at Netlify aims to lock folks in and take their money :slight_smile:


Also I think every service charges money at some point :stuck_out_tongue: Auth0 looks like you can get up to 7k users for free, but do remember that all of these companies are hosting, maintaining, and paying for running cloud hardware 24/7 to keep their services up. Nothing is free :grin:

Awesome, will look into the exporting. Thanks for that link.

When you’re using FaunaDB which already has user auth, it’s kind of redundant to use another auth system.

I can generate my own JWTs (in functions) based on the authorized FaunaDB user/role, and just pass that role information on to the host, but in this case, Netlify wouldn’t do the redirects based on the JWT unless using Business Plan.

Going the Identity route, I suppose I would dynamically create users/roles in FaunaDB based on the credentials generated by Identity.

Either way, I have to write code to keep the two identity systems in sync.

That’s correct, since Netlify would need to know the signing key used in your JWTs to truly verify the role object’s contents.

For what it’s worth, I’ve done this on production sites before - not with Fauna and Identity but actually with Identity and Contentful - where I keep a synced clone of each User so that the site admins can create content bound for each user specifically. Then when the end-user uses the website and gets to the ‘my-account’ sort of page, the front-end reaches out to a Netlify Function which verifies that the user is legit, then uses some ENV keys to reach out to Contentful and grab the content for that specific user.

There’s a few moving parts but it works surprisingly well. What helps is that Netlify has event-based Functions that can kick off from Identity events (a user logging in, a user signing up, etc.) and those Functions can be configured to run as ‘background functions’. Great for when you don’t want the sync process to prevent a user from signing in, but rather you want a background job to just make sure that user’s data is in sync with your second system :slight_smile:

Anyway, all that to say too, role-gated _redirects can be …touchy. Since they’re (httpOnly) cookie-based and can’t interface directly with javascript, the interop and workflow can be difficult. I encourage folks to go with the above route instead - using Identity JWTs to hit Functions (which get special powers when your site has Identity enabled) to serve private content. I think it’s more flexible and works better than creating static content that’s just role-gated. My 2c.


Ah so you’re serving SSR html layouts via Functions, based on Identity. That’s got to be slower than the host just serving static content.

To be able to redirect say /admin to /login at the server level, before any Functions run or html is served, is what I’m looking to achieve.

Also trying to avoid the synchronization routines that you’ve described above, if possible. However, good to know that that is working well for you.

I like the Event based Functions feature and background Functions features you mentioned, good work-arounds, but I would prefer just having one source of truth.

Yes, that’s the whole point, to have httpOnly secure cookie based tokens that can’t interact with javascript, that part is supposed to be difficult, strict. That is the most secure way to prevent XSS and CSRF, pass token information only in secure cookies, in the request headers between allowed domains. Letting the standard security protocols built into the browser do their thing.

Anyhow, rethinking strategies here.

Thanks for your helpful feedback. I’m sure it will be helpful to others as well.

1 Like