Home
Support Forums

Netlify Identity - Selective branches access control

Hi, I am trying to protect selective branches from traffic redirecting unauthorized users to another login site. I have enabled Netlify Identity on Login Site, invited myself and gave reviewer role to my user. Then I have created simple script to write _redirects file based on custom logic/branches, ending up with this:

/* /index.html 200! Role=reviewer

/* https://XXXX.netlify.app/login?site=https://deploy-preview-564--XXXX.netlify.app/:splat 302!

Then in Login Site I made a simple login which returns me Netlify Identity session with access_token and so on. I use that token to generate a cookie:

const cookie = require('cookie');

exports.handler = (event, context, callback) => {
  const {token} = JSON.parse(event.body);

  const expiry = Math.floor(Date.now() / 1000) + 60 * 60;

  const netlifyCookie = cookie.serialize('nf_jwt', token, {
    secure: true,
    path: '/',
    expires: new Date(expiry.toString()),
  });

  const response = {
    jwt: token,
    exp: expiry,
  };

  callback(null, {
    statusCode: 200,
    headers: {
      'Set-Cookie': netlifyCookie,
      'Cache-Control': 'no-cache',
    },
    body: JSON.stringify(response),
  });
};

After storing the cookie in users cookies I redirect user to the redirect function:

const parseURL = require('url-parse');
const cookie = require('cookie');

exports.handler = function (event, context, callback) {
  const {referer} = event.headers;

  const {site} = event.queryStringParameters;

  const urlData = parseURL(site);
  const siteOrigin = urlData.origin;

  //check that cookies are present
  const {headers} = event;
  const cookieHeader = headers.cookie || '';
  const cookies = cookie.parse(cookieHeader);

  if (cookieHeader === '' || !cookies.nf_jwt) {
    const redirectToURL = referer.match(/\?site=/g) ? referer : `${referer}?site=${site}`;

    return callback(null, {
      statusCode: 302,
      headers: {
        Location: redirectToURL,
        'Cache-Control': 'no-cache',
      },
      body: JSON.stringify({message: 'Token is not present'}),
    });
  }

  callback(null, {
    statusCode: 302,
    headers: {
      Location: `${siteOrigin}/.netlify/functions/set-cookie?token=${cookies.nf_jwt}&site=${site}`,
      'Cache-Control': 'no-cache',
    },
    body: null,
  });
};

This redirect invokes set-cookie function from the Gated Site:

const cookie = require('cookie');

exports.handler = (event, context, callback) => {
  const {token, site} = event.queryStringParameters;

  const twoWeeks = 14 * 24 * 3600000;

  const netlifyCookie = cookie.serialize('nf_jwt', token, {
    secure: true,
    httpOnly: true,
    path: '/',
    maxAge: twoWeeks,
  });

  const html = `
  <html lang="en">
    <head>
      <meta charset="utf-8">
    </head>
    <body>
      <noscript>
        <meta http-equiv="refresh" content="0; url=${site}" />
      </noscript>
    </body>
    <script>
      setTimeout(function(){
        window.location.href = ${JSON.stringify(site)}
      }, 0)
    </script>
  </html>`;

  callback(null, {
    statusCode: 200,
    headers: {
      'Set-Cookie': netlifyCookie,
      'Cache-Control': 'no-cache',
      'Content-Type': 'text/html',
    },
    body: html,
  });
};

The result is redirect back to login after successful Netlify Identity login - set-cookie returns 302 and seems like the redirect from _redirects is triggered, like if Role condition was not met. I have decoded the token and roles are ok. Requests sent from login action up to the redirect back to the login:

...
"app_metadata": {
  "provider": "email",
  "roles": [
    "reviewer"
  ]
},
...

I went through all Netlify docs and articles about the access control and I’m stuck here. One thing I noticed is that Netlify Identity token returns app_metadata.roles but docs about JWT access control says it should be app_metadata.authorization.roles - I could not map the token since I have no secret from Netlify Identity.

Thanks, help would be greatly apprieciated!

Disclaimer: I can only share the site to Netlify representatives.

Hi @AverageNetlifyBoi,

This will not work as both of those sites have a different JWT token. So the second site signs the token with a different secret than the one that’s trying to decode it. Thus, the roles never match. I believe on the Business plan you could set a custom JWT token, so if you sync the tokens on both sites, it should work.

I have set that - the same JWT Secret (Access Control) for both sites and behaviour is exactly the same.

In that case, the site name would be useful.