developers

Unlock Enterprise Readiness: How to Edit Existing Connections with Self-Service SSO in your SaaS App

In this blog post, we will add the capability to edit existing Self-Service SSO configurations in your SaaS application.

In the previous post, we added a Self-Service capability to create SSO connections. This is a powerful feature that you can use to offload administrative tasks to your customers' admins. However, your SaaS also needs to support editing the existing SSO configurations.

Creating SSO Connections Is a Must-Have

Let's discuss why editing is essential. After creating an SSO connection, a customer admin might need to update the Client Secret or swap the SAML certificate for the connection. In this scenario, the customer admin still needs to contact SaaS’s support or representatives.

To provide true “Self-Service” administration, you can continue to leverage the power of Auth0's Self-Service SSO feature. Let's dive into the details.

The Sample App

This blog post will use the sample application built previously as a starting point.

You can download a sample Node.js/Expression application:

git clone --branch feature/self-service-sso-create --single-branch https://github.com/neri78/self-service-sso-express.git

Note: The sample code omits error handling to make the code simple. In a real-world development, you will need to implement error handling correctly.

Follow the attached README file instructions to register and configure the Regular Web Application and a Machine-to-Machine (M2M) Application.

In the sample app, once you have signed up as a user and logged in, click Dashboard on the header navigation to open the dashboard page. You will see the following page on the navigation to the Dashboard page. Currently, the Dashboard provides a button to create a new SSO Connection.

Self-Service Editing for SSO Connections

To add editing capability to the sample application, we will perform the following steps:

  1. Update the UI on the Dashboard page.
  2. Add a permission for the Management API to retrieve existing connections.
  3. Update router handler to create a Self-Service SSO editing.

Update the UI on the dashboard page

First, let's add an Edit button on the views/dashboard.ejs file:

<!-- ...existing code.. -->
   <form action="/dashboard" method="post" class="w-full max-w-xl">
     <div class="md:flex md:items-center">
       <div >
       <!-- 👇 change code -->
         <button class="shadow bg-indigo-600 hover:bg-indigo-500 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"
                 name="action"
                 value="create"
                 type="submit">
           Add SSO Connection
         </button>
         <p>or</p>
         <button class="shadow bg-indigo-600 hover:bg-indigo-500 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"
                 name="action"
                 value="edit"       
                 type="submit">
           Edit SSO Connection
         </button>
       <!-- 👆 change code -->
       </div>
     </div>
   </form>
<!-- ...existing code.. -->

Now, the dashboard has two buttons. Each button has a value attribute, which is used to branch logic in the router handler.

Add a Permission for the Management API to retrieve existing connections

We must retrieve existing connections using the Auth0 Management API to edit an existing connection. For those purposes, grant the following permission in your Machine-to-Machine (M2M) application:

  • read:connections

Update Router Handler to Create a Self-Service SSO Editing

The application has a POST handler for /dashboard in the router/index.js file. This handler is creating a Self-Service SSO ticket to create a connection. We are going to use this handler for editing, too.

Branch the logic

Let's update the handler to branch based on the button's value attribute.

// routes/index.js


// ...existing code...
router.post('/dashboard', requiresAuth(), async function (req, res, next) {
   // get an instance of the ManagementClient.
   const management = getManagementClient();


   // get a list of Self-Service Profiles.
   const { data: ssoProfiles } = await management.selfServiceProfiles.getAll();


   // use the 1st profile in this sample.
   const ssoProfile = ssoProfiles[0];


   const requestParameters = {
       id: ssoProfile.id
   };


   // 👇 change code
   let bodyParameters = {};


   const action = req.body.action;


   if (action === 'create') {
       // build bodyParameter for 'create a connection'.
       bodyParameters = {
           ...bodyParameters,
           connection_config: { name: `self-service-sso-${Date.now()}` },
           enabled_clients: [process.env.CLIENT_ID]
       }
   } else if (action === 'edit') {
       // build bodyParameter for 'edit a connection'.
   }
   // 👆 change code


   // generate a Self-Service SSO ticket.
   const { data: ssoTicket } =
       await management.selfServiceProfiles.createSsoTicket(
           requestParameters,
           bodyParameters
       );




   res.render('dashboard', {
       title: 'Admin Dashboard',
       ticketURL: ssoTicket.ticket
   });
});
// ...existing code...

With this change, we can keep the existing logic for creating new connections.

Build a bodyParameter to edit an existing connection

To edit an existing connection with the Self-Service SSO, specify connection_id in the bodyParameters. Here's the updated code:

// routes/index.js


//...existing code...
router.post('/dashboard', requiresAuth(), async function (req, res, next) {
   // get an instance of the ManagementClient.
   const management = getManagementClient();


   // get a list of Self-Service Profiles.
   const { data: ssoProfiles } = await management.selfServiceProfiles.getAll();


   // use the 1st profile in this sample.
   const ssoProfile = ssoProfiles[0];


   const requestParameters = {
       id: ssoProfile.id
   };


   let bodyParameters = {};
   const action = req.body.action;


   if (action === 'create') {
       // build bodyParameter for 'create a connection'.
       bodyParameters = {
           ...bodyParameters,
           connection_config: { name: `self-service-sso-${Date.now()}` },
           enabled_clients: [process.env.CLIENT_ID]
       }
   } else if (action === 'edit') {


       // build bodyParameter for 'edit a connection'.
       // 👇 add code
       // get connections for the current client
       const { data: enabledConnections } = await management.clients.getEnabledConnections({
           client_id: process.env.CLIENT_ID
       });


       // filter a connection with the name and use the first item for this sample.
       const ssoConnection = enabledConnections.connections.filter(connection => {
       return connection.name.includes('self-service-sso-')
       })[0];


       // add connection_id to the bodyParameter.
       bodyParameters = {
           ...bodyParameters,
           connection_id: ssoConnection.id
       };
       // 👆 add code
   }


   // generate a Self-Service SSO ticket.
   const { data: ssoTicket } =
       await management.selfServiceProfiles.createSsoTicket(
           requestParameters,
           bodyParameters
       );


   res.render('dashboard', {
       title: 'Admin Dashboard',
       ticketURL: ssoTicket.ticket
   });
});
// ...existing code...

Let's see the details of the code.

Retrieve an existing connection

We need to get the id of the connection we want to edit. You can use the Get enabled connections for a client endpoint to get a list of connections for the current Auth0 Application and filter the list with condition(s).

// get connections for the current client
const { data: enabledConnections } = await management.clients.getEnabledConnections({
   client_id: process.env.CLIENT_ID
});


// filter a connection with the name and use the first item for this sample.
const ssoConnection = enabledConnections.connections.filter(connection => {
   return connection.name.includes('self-service-sso-')
})[0];

management.clients.getEnabledConnections() method retrieves a list of connections for a specified Auth0 client (application). Because we created a Self-Service SSO connection with a naming convention in the previous post, we can apply a filter to the list with the following condition:

  • The name of the connection includes self-service-sso-.

This blog post assumes the first connection that matches the condition is appropriate.

If you are using Auth0 Organizations, you can use the Get connections enabled for an organization endpoint instead. The auth0-node supports this endpoint, too. Make sure the machine-to-machine application has read:organization_connections permission for the Auth0 Management API access. In another post, I will cover the combination of Self-Service SSO and Auth0 Organizations.

Set connection_id in the bodyParameter

The final step is to set the connection_id value in the bodyParameter

 // add connection_id to the bodyParameter.
 bodyParameters = {
   ...bodyParameters,
   connection_id: ssoConnection.id
 };

That's all. Now, everything is set to create a Self-Service SSO Ticket to edit an existing connection. We can keep using existing code to generate a ticket:

 // generate a Self-Service SSO ticket
 const ssoTicket = await management.selfServiceProfiles.createSsoTicket(
   requestParameters,
   bodyParameters
 );

Let’s See It in Action!

When you click the Edit SSO Connection button on the dashboard page, you will see the following page with another button that opens the URL of the generated ticket.

When you click the button, the browser opens a new tab with the SSO setup assistant page and the current connection settings. Customer admins can change settings here.

Conclusion

In this post, you learned how to:

  • Update the application to generate a Self-Service SSO ticket for an existing connection.

With the creation and editing capabilities of Self-Service SSO, you can provide a delegate administration feature in your SaaS. In the following posts, I will cover the details of the Self-Service profile and using this feature with Auth0 Organizations for a B2B SaaS scenario.

Try with SaaStart: Next.js B2B SaaS Reference Application

Auth0 provides features for building a B2B SaaS application. In this post, I used Node.js/Express to showcase one of its features. If you are considering building a B2B SaaS in Next.js, try SaaStart. The app provides reference implementations of necessary features for B2B SaaS, such as multi-tenancy, login options for enterprise users, security policies, and more.

SaaStart App GitHub