How to build a user management dashboard with WorkOS and Node
Step-by-step tutorial on how to add basic user management functionality to your app using Node.js and WorkOS.
Once you have users in your app, you must start managing them. You need a dashboard screen where you can list your users, change their permissions, revoke their access, or invite new ones.
In this tutorial, we will see how you can do all of the above with WorkOS and Node.js.
If you haven’t implemented user authentication yet, then do that first. You can use one of these guides to get started:
- How to build SAML SSO with WorkOS, Okta, and Node
- How to build SAML SSO with WorkOS, Entra ID, and Node
- SSO with other identity providers
- Social login quickstart
Prerequisites
To follow this tutorial, you will need the following:
Step 1: Install the SDK
Install the WorkOS Node SDK to your app.
Via npm:
Via yarn:
Via pnpm:
Step 2: Set secrets
To make calls to WorkOS, you must authenticate using the WorkOS API key and client ID. Copy these values from the WorkOS dashboard.
Store the values as managed secrets and pass them to the SDK either as environment variables or directly in your app’s configuration.
Environment variables example:
For more info on how to handle secrets safely see Best practices for secrets management.
Step 3: Set up the backend
We are ready to start adding code. We will implement the following functionality:
- List users.
- Remove users that should no longer have access.
- Change what role a user has.
- Invite new users (with the ability to re-send and revoke invitations).
We will present two different implementations.
The first option uses WorkOS Widgets: React components that provide complete functionality for common enterprise app workflows. The Users Management Widget provides a UI for inviting, removing and editing users and is available for free to all AuthKit customers.
Here is a quick demo on how Widgets work:
If you prefer to build and manage your own authentication UI, or you don’t want to use Widgets, follow the second option. It will show you how to implement this functionality via the User Management API.
Option 1: Use Widgets
1. Install the Widgets package
First, install the @workos-inc/widgets
package from the npm registry, along with its peer dependencies:
2. Configure CORS
Because WorkOS widgets issue client-side requests to WorkOS, it is necessary to configure your site as an allowed web origin. Go to WorkOS dashboard> Authentication > Cross-Origin Resource Sharing (CORS) > Configure CORS and add your app’s URL.
3. Add the widget
Widgets need to authenticate with the WorkOS API and for that they need a token. How you will get one depends on whether you use AuthKit or not.
If you are using the authkit-js or authkit-react libraries, you can use the provided access token, returned by getAccessToken
. Use this code sample to get a token and add the widget to your app:
If you use one of our backend SDKs, use the get token method in the SDK to request a token. You need to specify which widget you want the token for (using scopes
) and who is the user using the widget (using userId
and organizationId
).
Use this code sample to get a token and add the User Management widget to your app:
Note the following to avoid errors:
- Widget tokens expire after one hour.
- To successfully generate a token, the user must have the correct permissions. New WorkOS accounts are created with an “Admin” role that has all Widget permissions assigned, but existing accounts will need to be updated. In order to use the User Management widget, a user must have a role that has the
widgets:users-table:manage
permission. This can be done on the “Roles” page of the WorkOS dashboard. For more info see the Roles and Permissions docs.
That’s it, your user management dashboard is ready to go!
4. Customize the UI (optional)
WorkOS Widgets are powered by Radix Themes, which are styled out-of-the box when you import its CSS in your app.
You can customize Widgets by passing a theme
prop to WorkOSWidgets
. This prop accepts an object with the same options as Radix themes.
You can also style Widgets using CSS. Start with the layout.css
stylesheet from Radix Themes, as well as the base.css
stylesheet from WorkOS Widgets, to get a base level of functional styling without opinionated design choices.
Individual elements in Radix themes are accessible via CSS class selectors prefixed with woswidgets-
. For example, you can add your own button styles by selecting the woswidgets-button
class.
Option 2: Manual implementation
Follow this section if you prefer to build and manage your own authentication UI, or you don’t want to use Widgets. We will not go into the frontend details but will see how to implement this functionality in the backend via the User Management Authentication API.
We will build the following functionality:
- List users.
- Remove a user.
- Update a user’s role.
- Invite a new user.
List users
We will start with listing all the users that belong to the same organization as the logged in user.
An organization is a collection of users that also acts as a container for enterprise features (like SSO). By enabling a feature for a specific organization, you enable it for all users who are members of this organization. This way, you can enable features like forcing all users that use a specific email domain to use a specific SSO connection. For more information on organizations and how to use them, see Model your B2B SaaS with organizations.
You can list users using the listUsers() SDK method.
You can also set as input parameters the organizationId
(if you want to list users of another organization) or the email
(if you want filter users by their email).
This is what the result looks like for the example we just saw:
Note that since an org can have many users, this endpoint is paginated. WorkOS pagination uses 4 parameters:
limit
: How many objects to return (1-100). The default value is 10.order
: Order the results by the creation time. Supported values are"asc"
and"desc"
for showing older and newer records first respectively. Default order is descending.before
andafter
:Object IDs that define your place in the list. When the IDs are not present, you are at the end of the list. For example, if you make a list request and receive 100 objects, ending with"obj_123"
, your subsequent call can includeafter="obj_123"
to fetch a new batch of objects before or after"obj_123"
.
Remove user
We will continue with adding an endpoint that removes a user from the org. For that we will use the deleteOrganizationMembership() SDK method.
When a user is added to the org an org membership is created. Each membership has a unique ID and you need to know it in order to remove the user from that org:
To get the organization membership ID, you can list the orgs a user belongs to using listOrganizationMemberships():
Assuming you know the organization ID, you can parse the results, read the membership ID, and use it to remove the user from the org:
With this flow the user will remain in your system but will not have access to that organization. If this is not the behavior you want, you also have this options:
- Delete the user.
- Deactivate the organization membership instead of deleting it.
- Deactivating an organization membership sets its status to
inactive
and revokes all active sessions. At a later point, you can reactivate the organization membership. This will set its status back toactive
. The user will retain the roles they had prior to deactivation. - Note that
pending
memberships cannot be deactivated and should be deleted using the deleting membership API instead. Likewise,pending
memberships cannot be reactivated. For this the user should go through the invitation acceptance flow instead. If invitations are not needed, the organization membership can be created as active directly.
- Deactivating an organization membership sets its status to
List a user’s roles
To retrieve and display a user’s role, use the listOrganizationMemberships() SDK method:
Update a user’s roles
To change a user’s roles for a specific org, you must know the organization membership ID. Use the updateOrganizationMembership() SDK method:
To get the organization membership ID, list the orgs the user belongs to.
Invite new users
You can invite users to sign up for your app and join an org using the sendInvitation() SDK method:
Other input parameters you can use are:
organizationId
: The ID of the organization that the recipient will join.expiresInDays
: How many days the invitations will be valid for (range=1-30, default=7).inviterUserId
: The ID of the user who invites the recipient. The invitation email will mention the name of this user.roleSlug
: The role that the recipient will receive when they join the organization in the invitation.
If you don’t set an organizationId
, the user will be able to join the application but won’t be added to any org.
If you want to re-send an invitation you have to first revoke it, and then send a new one.
Revoke an invitation
To revoke an invitation you have sent out, use the revokeInvitation() SDK method:
You can list an organization’s invitations to find the ID of the one you are looking for.
Next steps
You have now built basic user management functionality in your app. This might not be exciting but it’s basic functionality that every app needs.
Assuming that this was maybe your second step, with the first being authentication, there are still many more in your journey into the authentication and authorization world. The next steps can be things like handling the user’s session, implementing access control, provisioning users automatically, handling failed authentication events, and more. Stay tuned for follow up tutorials on all of these areas.
Here are some resources you might find useful:
- User management quickstart: A complete authentication platform that uses AuthKit and includes SSO out of the box.
- AuthKit branding docs: How to customize the look and feel of AuthKit to match your app’s design.
- SSO quickstart: A standalone API for integrating into an existing auth stack.
- Example applications:
- Node.js SSO sample application: An example application demonstrating how to use the WorkOS Node.js SDK to authenticate users via SSO.
- Next.js integration example using AuthKit: An example application demonstrating how to authenticate users with AuthKit and the WorkOS Node.js SDK.
- Admin Portal docs: An out-of-the-box UI for IT admins to configure SSO connections.
- Migration guides: Detailed instructions on how to migrate your users from another service to WorkOS.
- Passkeys: How to use passkeys and AuthKit for a seamless and secure login experience.