Netlify Identity Role based Access control not working

I’ll give you some details for if you want to do some further investigating.

Netlify domain

moonface.netlify.app

Git repo

https://github.com/kylesloper/moonface

Hey @kylesloper as @jonsully says it can be complicated but after much pain andsicussion with John I got it working in my protype app - with no client side routing. I’ve just made it open source in case it helps.

So first thing is you need to ensure the browser gets a redirect for the routes in question. This is done by adding another rule for 302.

In this case I have these roles:

  • none - access public home page
  • rdm - plus access to /rdm
  • applicant - plus access / applicant
  • admin - plus access to everyhting

I found all sorts of weird edge cases and even some browser specific issues. In the end the code encapsulates a working version that handles all the cases and browsers I threw at it.

It is also uses the free (starter) plan, is based on 11ty and I used Firefox for dev :slight_smile:

If I get time I’ll distill the auth / routing logic and do something like an egghead lesson.

Hope that helps

1 Like

Thanks for the detailed explanation man.

Just to be clear, do both rdm and applicant reassemble protected pages? I simply exchanged /rdm/* with pages of my own and it still doesn’t seem to work.

Yes, I used the same name for role and protected routes but thats not necessary.

If I recall correctly, applicant role is give to anyone who signs up but run is added manually using the netlify control panel.

Does the routing definitely get correctly deployed to the CDN?

1 Like

I don’t entirely know what you mean by if the routing is passed but I’ve just seen that no redirect rules are actually processed on deployment.

Deploy details | moonface (netlify.com)

Hey @kylesloper :wave:t2:

Sorry to be a little slow to get back to you! For starters, @slim and myself have done a lot of digging, playing, and research with role-gated _redirects over the past several months. They can work, but they do have pros and cons. There’s actually another thread going right now along the same lines. I’d recommend you give it a read -

That said, yes, the “No redirect rules processed” is definitely preventing you from even getting your foot in the door :stuck_out_tongue: Taking a look at your repository, the issue lies in the structure: A _redirects file needs to ultimately end up in your publish directory. You have it in your root directory but your netlify.toml shows a publish directory of ./_site. I see you’re using Eleventy, which, by default does not publish files it’s unaware of or not processing. To fix that, you’ll just need to add

eleventyConfig.addPassthroughCopy("_redirects");

To your .eleventy.js file :slight_smile:

Cheers!


Jon

1 Like

Thankyou @jonsully and @slim for your work with role based redirects.
I’ve added the passthrough into eleventy.js and now the UI shows that redirect rules are actually being processed.

Unfortunately still no luck with the actual role based access control since it will only redirect to the fallback method and take the user to the home page even when the user has been authenticated and has the relevant roles.

Just asking the baseline question here, but have you verified that the role is actually applied to the user? And logged out / back in to ensure that the new JWT is in the browser?


Jon

Yes I have. Even deleted and remade the user entirely.

Update

Now recieving this error in cli:

◈ Reloading redirect rules from [ '_site\\_redirects', '_redirects', 'netlify.toml' ]
◈ Reloading redirect rules from [ '_site\\_redirects', '_redirects', 'netlify.toml' ]
◈ Reloading redirect rules from [ '_site\\_redirects', '_redirects', 'netlify.toml' ]
◈ Reloading redirect rules from [ '_site\\_redirects', '_redirects', 'netlify.toml' ]
◈ Reloading redirect rules from [ '_site\\_redirects', '_redirects', 'netlify.toml' ]
◈ Reloading redirect rules from [ '_site\\_redirects', '_redirects', 'netlify.toml' ]
◈ Reloading redirect rules from [ '_site\\_redirects', '_redirects', 'netlify.toml' ]
 [Error: EPERM: operation not permitted, stat 'C:\Users\kyles\Desktop\moonface\_site\_redirects'] {
 errno: -4048,
 code: 'EPERM',
 syscall: 'stat',
 path: 'C:\\Users\\kyles\\Desktop\\moonface\\_site\\_redirects'
 }
 [Error: EPERM: operation not permitted, stat 'C:\Users\kyles\Desktop\moonface\_site\_redirects'] {
 errno: -4048,
 code: 'EPERM',
 syscall: 'stat',
 path: 'C:\\Users\\kyles\\Desktop\\moonface\\_site\\_redirects'
 }

Hey @kylesloper,
Sorry for the long delay here and thanks for bearing with us- you caught us over a very short-staffed chunk of the holidays. Thankfully, you were in great hands with @jonsully and @slim. I took a look at your site and see that you were successfully deploying redirect rules for a while, but not anymore. Have you decided to go the frontend routing route? Or should we dig into this issue with your redirects file?

1 Like

Yea I would appreciate if we were to be able to look into the issue with the redirects.

Great! To get back to a fresh slate on this issue (since there have been several deploys in the meantime), can you please add the redirects for Identity to your netlify.toml and share a link to your deploy log when that’s done? I’ll take a look at what our build system picked up (or didn’t) and check our logs for any errors.

1 Like

Yea sure. Quick question: is is necessary to use netlify.toml in this instance or is the normal _redirects file okay?

I have seen some issues where non-printing bytes prevent _redirects and _headers files from being uploaded (see:

and you also have to make sure they end up in the right published directory… so when debugging, I prefer to stick with netlify.toml in the root directory if it’s alright with you!

1 Like

Yea sure!

I added the redirects in like this, I never touch netlify.toml so It’s causing an error.

[build]
  publish = "_site"
  command = "eleventy"

# REDIRECT and HEADERS examples

# Redirect rule example
# For more information see:- https://www.netlify.com/docs/netlify-toml-reference/

#[[redirects]]
#  from = "/*"
#  to = "/blog/:splat"
# Two-step role-gate with fallback to home page
/rates/*	      200!  Role=rdm,admin
/rates/*   /    302!

# The default HTTP status code is 301, but you can define a different one e.g.
# status = 302

# Headers rule example
# For more information see:- https://www.netlify.com/docs/netlify-toml-reference/

#[[headers]]
#   Define which paths this specific [[headers]] block will cover.
#   for = "/*"

#[headers.values]
#   X-Frame-Options = "DENY"
#   X-XSS-Protection = "1; mode=block"
#   Content-Security-Policy = "frame-ancestors https://www.facebook.com"

# Redirects and headers are GLOBAL for all builds – they do not get scoped to
# contexts no matter where you define them in the file.
# For context-specific rules, use _headers or _redirects files, which are
# applied on a PER-DEPLOY basis.

Here is the error

◈ Reloading redirect rules from [ '_site\\_redirects', 'netlify.toml' ]
[SyntaxError: When resolving config file C:\Users\kyles\Desktop\moonface\netlify.toml:
Could not parse configuration file
Expected "#", "'", "[", "\"", "\n", "\r", [ \t], [A-Za-z0-9_\-] or end of input but "/" found.] {
  expected: [
    { type: 'literal', value: '#', description: '"#"' },
    { type: 'literal', value: "'", description: `"'"` },
    { type: 'literal', value: '[', description: '"["' },
    { type: 'literal', value: '"', description: '"\\""' },
    { type: 'literal', value: '\n', description: '"\\n"' },
    { type: 'literal', value: '\r', description: '"\\r"' },
    { type: 'class', value: '[ \\t]', description: '[ \\t]' },
    {
      type: 'class',
      value: '[A-Za-z0-9_\\-]',
      description: '[A-Za-z0-9_\\-]'
    },
    { type: 'end', description: 'end of input' }
  ],
  found: '/',
  offset: 293,
  line: 14,
  column: 1,
  type: 'userError'
}
[SyntaxError: When resolving config file C:\Users\kyles\Desktop\moonface\netlify.toml:
Could not parse configuration file
Expected "#", "'", "[", "\"", "\n", "\r", [ \t], [A-Za-z0-9_\-] or end of input but "/" found.] {
  expected: [
    { type: 'literal', value: '#', description: '"#"' },
    { type: 'literal', value: "'", description: `"'"` },
    { type: 'literal', value: '[', description: '"["' },
    { type: 'literal', value: '"', description: '"\\""' },
    { type: 'literal', value: '\n', description: '"\\n"' },
    { type: 'literal', value: '\r', description: '"\\r"' },
    { type: 'class', value: '[ \\t]', description: '[ \\t]' },
    {
      type: 'class',
      value: '[A-Za-z0-9_\\-]',
      description: '[A-Za-z0-9_\\-]'
    },
    { type: 'end', description: 'end of input' }
  ],
  found: '/',
  offset: 293,
  line: 14,
  column: 1,
  type: 'userError'
}

C:\Users\kyles\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\netlify-redirector\lib\redirects.js:116
      throw ex;
      ^
abort({"message":"When resolving config file C:\\Users\\kyles\\Desktop\\moonface\\netlify.toml:\nCould not parse configuration file\nExpected \"#\", \"'\", \"[\", \"\\\"\", \"\\n\", \"\\r\", [ \\t], [A-Za-z0-9_\\-] or end of input but \"/\" found.","expected":[{"type":"literal","value":"#","description":"\"#\""},{"type":"literal","value":"'","description":"\"'\""},{"type":"literal","value":"[","description":"\"[\""},{"type":"literal","value":"\"","description":"\"\\\"\""},{"type":"literal","value":"\n","description":"\"\\n\""},{"type":"literal","value":"\r","description":"\"\\r\""},{"type":"class","value":"[ \\t]","description":"[ \\t]"},{"type":"class","value":"[A-Za-z0-9_\\-]","description":"[A-Za-z0-9_\\-]"},{"type":"end","description":"end of input"}],"found":"/","offset":293,"line":14,"column":1,"name":"SyntaxError","type":"userError"}) at Error
    at jsStackTrace (C:\Users\kyles\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\netlify-redirector\lib\redirects.js:1070:13)
    at stackTrace (C:\Users\kyles\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\netlify-redirector\lib\redirects.js:1087:12)
    at process.abort (C:\Users\kyles\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\netlify-redirector\lib\redirects.js:8502:44)
    at process.emit (events.js:315:20)
    at processEmit [as emit] (C:\Users\kyles\AppData\Roaming\npm\node_modules\netlify-cli\node_modules\signal-exit\index.js:161:32)
    at processPromiseRejections (internal/process/promises.js:245:33)
    at processTicksAndRejections (internal/process/task_queues.js:94:32)
(Use `node --trace-uncaught ...` to show where the exception was thrown)

Ah no worries, that’s a formatting issue. For the netlify.toml, you’ll want to add them like this:

[[redirects]]
from = "/rates/*"
force = true
status = 200
conditions = {Role = ["rdm", "admin"]}

[[redirects]]
from = "/rates/*"
to = "/"
force = true
status = 302
1 Like

Here is the deploy log :))

Deploy details | moonface (netlify.com)

Nice, looks like the redirects were correctly processed there :tada: When I click “LOGIN” on your site, I get through the flow and am able to login. Can you see what happens when you try?

Just wondering which login you are clicking, when I am in testing, /login is the page with Netlify identity login.

When logged out, /rates redirects back to / however when I log in the same happens. When logged in as a user with an admin role, I still get redirected to /

If it’s any help to you I can invite you so that you could test it out.