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:
- Update the UI on the Dashboard page.
- Add a permission for the Management API to retrieve existing connections.
- 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 hasread: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.
About the author

Daizen Ikahara
Principal Developer Advocate
.NETエンジニアとしてキャリアをスタートさせた後、UIコンポーネントベンダーやクラウドコミュニケーションプラットフォームベンダーにおいて様々なロールを歴任。2023年3月よりOktaに参画し、日本市場における開発者リレーションを担当。趣味はゲームと長距離散歩。
Daizen Ikehara joined the Developer Relations team in March 2023 as a Principal Developer Advocate. In the early stages of his professional career, Daizen started using C#. Then, he touched on various JavaScript technologies/frameworks—Angular, React, and Vue. Recently, he’s been using Node.js/JavaScript more often. He is passionate about talking with developers. Outside of work, Daizen likes to take long walks, play video games, and watch Formula 1 racing.