Build: [Plugin idea] Auth0 custom domain + callback url updater

Created on 6 Jan 2020  ·  8Comments  ·  Source: netlify/build

When using auth0, you have to hardcode the URLs that your auth0 instance will use. This causes issues with auth flows not working with Netlify deploy previews.

With a build plugin, you could automatically set the deploy preview URLs as the allowed URLs in the auth0 client settings using the https://auth0.com/docs/api/management/v2 ref

https://auth0.com/docs/api/management/v2#!/Clients/patch_clients_by_id

This would allow auth flows to work even in a Netlify preview url context.

(Optionally the plugin could remove older preview URLs from the list to clean itself up.)


Context: Without this, it's not possible to fully test applications with auth flows while using auth0

enhancement plugin idea

Most helpful comment

/* eslint-disable no-console */
const path = require('path');
require('dotenv').config({
  path: path.resolve(process.cwd(), `.env.${process.env.CONTEXT}`),
});
const { ManagementClient } = require('auth0');

module.exports = {
  onInit: ({ utils }) => {
    console.info(`🔑 Auth0 Plugin startup 🔑`);
    const tab = '   ';
    const requiredEnvVariables = [
      'AUTH0_MANAGEMENT_API_TOKEN',
      'AUTH0_DOMAIN',
      'AUTH0_CLIENT_ID',
      'AUTH0_CALLBACK_PATHNAMES',
      'AUTH0_LOGOUT_PATHNAMES',
      'DEPLOY_URL',
    ];
    const missingEnvVariables = requiredEnvVariables.filter(
      envVar => typeof process.env[envVar] === 'undefined',
    );

    if (missingEnvVariables.length > 0) {
      utils.build.failPlugin(
        `${tab} ☠️ Missing environment variables: ${missingEnvVariables.join(
          ', ',
        )}`,
      );
    }

    return new Promise(resolve => {
      const url = process.env.DEPLOY_URL;
      console.log(`${tab} 🧭 Deploy Preview URL should be:`, url);
      const management = new ManagementClient({
        token: process.env.AUTH0_MANAGEMENT_API_TOKEN,
        domain: process.env.AUTH0_DOMAIN,
      });

      management.clients
        .get({ client_id: process.env.AUTH0_CLIENT_ID })
        .then(client => {
          console.info(`${tab} 🗝 Retrieved Auth0 client:`, client.name);
          if (client.allowed_clients.indexOf(url) === -1) {
            console.info(`${tab} URL has not yet been added to Auth0 Client`);
            const payload = {
              allowed_clients: client.allowed_clients.concat([url]),
              web_origins: client.allowed_clients.concat([url]),
              allowed_origins: client.allowed_clients.concat([url]),
              callbacks: client.callbacks.concat(
                process.env.AUTH0_CALLBACK_PATHNAMES.split(',').map(
                  pathname => `${url}/${pathname}`,
                ),
              ),
              allowed_logout_urls: client.callbacks.concat(
                process.env.AUTH0_LOGOUT_PATHNAMES.split(',').map(
                  pathname => `${url}/${pathname}`,
                ),
              ),
            };
            management.clients.update(
              { client_id: process.env.AUTH0_CLIENT_ID },
              payload,
              (updateError, updatedClient) => {
                if (updateError) {
                  utils.build.failPlugin(
                    `${tab} ☠️ Something wrong happened while trying to patch Auth0 Client`,
                  );
                } else {
                  console.log(`${tab} 🍾 Successfully patched Auth0 Client.`);
                  console.log(
                    `${tab} Allowed URLS:`,
                    updatedClient.allowed_clients,
                  );
                }
                resolve();
              },
            );
          } else {
            console.info(
              `${tab} 👍 URL has already been added to Auth0 Client`,
            );
            resolve();
          }
        });
    });
  },
};

Here's what I came up with. It seems to be working on our Deploy Previews as on our Production Deploys. Feel free to create an official plugin and re-use this code !

All 8 comments

I'm definitely digging this idea, having the same exact problem right now.

This would require to

  • have the user add a AUTH0_CLIENT_ID and AUTH0_MANAGEMENT_API_TOKEN in the environment variables

  • send a GET request to /api/v2/clients/{id} to get the values of the callbackURLs and allowedURLs

  • send a PATCH request to /api/v2/clients/{id} with the added URL

The caveats I see : does the AUTH0_MANAGEMENT_API_TOKEN has to be refreshed ?

/* eslint-disable no-console */
const path = require('path');
require('dotenv').config({
  path: path.resolve(process.cwd(), `.env.${process.env.CONTEXT}`),
});
const { ManagementClient } = require('auth0');

module.exports = {
  onInit: ({ utils }) => {
    console.info(`🔑 Auth0 Plugin startup 🔑`);
    const tab = '   ';
    const requiredEnvVariables = [
      'AUTH0_MANAGEMENT_API_TOKEN',
      'AUTH0_DOMAIN',
      'AUTH0_CLIENT_ID',
      'AUTH0_CALLBACK_PATHNAMES',
      'AUTH0_LOGOUT_PATHNAMES',
      'DEPLOY_URL',
    ];
    const missingEnvVariables = requiredEnvVariables.filter(
      envVar => typeof process.env[envVar] === 'undefined',
    );

    if (missingEnvVariables.length > 0) {
      utils.build.failPlugin(
        `${tab} ☠️ Missing environment variables: ${missingEnvVariables.join(
          ', ',
        )}`,
      );
    }

    return new Promise(resolve => {
      const url = process.env.DEPLOY_URL;
      console.log(`${tab} 🧭 Deploy Preview URL should be:`, url);
      const management = new ManagementClient({
        token: process.env.AUTH0_MANAGEMENT_API_TOKEN,
        domain: process.env.AUTH0_DOMAIN,
      });

      management.clients
        .get({ client_id: process.env.AUTH0_CLIENT_ID })
        .then(client => {
          console.info(`${tab} 🗝 Retrieved Auth0 client:`, client.name);
          if (client.allowed_clients.indexOf(url) === -1) {
            console.info(`${tab} URL has not yet been added to Auth0 Client`);
            const payload = {
              allowed_clients: client.allowed_clients.concat([url]),
              web_origins: client.allowed_clients.concat([url]),
              allowed_origins: client.allowed_clients.concat([url]),
              callbacks: client.callbacks.concat(
                process.env.AUTH0_CALLBACK_PATHNAMES.split(',').map(
                  pathname => `${url}/${pathname}`,
                ),
              ),
              allowed_logout_urls: client.callbacks.concat(
                process.env.AUTH0_LOGOUT_PATHNAMES.split(',').map(
                  pathname => `${url}/${pathname}`,
                ),
              ),
            };
            management.clients.update(
              { client_id: process.env.AUTH0_CLIENT_ID },
              payload,
              (updateError, updatedClient) => {
                if (updateError) {
                  utils.build.failPlugin(
                    `${tab} ☠️ Something wrong happened while trying to patch Auth0 Client`,
                  );
                } else {
                  console.log(`${tab} 🍾 Successfully patched Auth0 Client.`);
                  console.log(
                    `${tab} Allowed URLS:`,
                    updatedClient.allowed_clients,
                  );
                }
                resolve();
              },
            );
          } else {
            console.info(
              `${tab} 👍 URL has already been added to Auth0 Client`,
            );
            resolve();
          }
        });
    });
  },
};

Here's what I came up with. It seems to be working on our Deploy Previews as on our Production Deploys. Feel free to create an official plugin and re-use this code !

This is fantastic @romainbessugesmeusy! Nice work.

Are you planning on publishing this to npm? 😃

Thank you for your kind words! I fear I won’t be able to maintain such a project and I probably won’t be doing a service to the community by doing it poorly. Feel free to publish it yourself if you want. Cheers and stay safe

@romainbessugesmeusy, Thanks for sharing this and allowing the code for re-use. Even if you can't maintain something like this, it's kind of you to share with the community after finding a solution.

Latest netlify-build broke local plugins so I add to publish it. https://www.npmjs.com/package/netlify-plugin-auth0-patch-urls

Latest netlify-build broke local plugins so I add to publish it. https://www.npmjs.com/package/netlify-plugin-auth0-patch-urls

Just added 2 PRs to the repo. Thanks for sharing this with the community

Last one, to allow the DEPLOY PRIME URL :+1:

Was this page helpful?
0 / 5 - 0 ratings