A Solutions Engineer's Guide to Building a B2B SaaS App

By: Mark Vong, Calah Vargas, Shreya Gupta

TLDR: This is a transcript of the “Building a B2B SaaS App” workshop presented by Mark Vong (Solutions Engineer at Okta). This workshop was organized by Auth0 for Startups, designed for anyone looking for best practices around:

  • Managing business users and their permissions,
  • Customizing the authentication experience for everyone,
  • And extending the ability for businesses to manage themselves.

Let us know in the comments below if you have any questions on this guide or want to be invited to any of our upcoming events!

A Solutions Engineer’s Guide to Building a B2B SaaS App

Startup developers face the challenge of building an MVP that is:

  • Quick to implement
  • Easy to iterate on and scalable
  • Adheres to industry authentication and security standards/regulations

Our goals

With our platform, we aim to solve for as many as possible of these use cases, with specific features and the following key outcomes:

  • Outcome #1 - Faster time to market
    • Organizations - Organizations allow us to easily implement a version of a multi-tenanted application, so you don’t have to build your own and scale it in a way that might be too difficult to manage. You can have different customer tenants of your application, all within a single authentication platform.
    • Lazy Migration - Port over your users seamlessly and dynamically without causing any disruption. You don’t have to go through the hassle of doing a bulk migration and dealing with non-migrated identities. However, we do also support bulk migration.
  • Outcome #2 - Shorter customer time to value
    • Marketplace - Meet your customers’ unique business needs by using pre-built integrations. Build out the flow that is specific to your business needs.
    • Actions - Actions are custom Node.js functions that allow you to fully control both the authentication and registration flows.
    • Account linking - The ability to remove duplicate user profiles by linking disparate identities to form a single cohesive and unified user identity. This can be accomplished using a pre-built extension or implemented using the management API.
  • Outcome #3 - Frictionless customer experience
    • Custom Branding - Customize the look and feel of the hosted login page using either a no-code or a fully programmatic approach. Bring your own style sheets and add custom HTML elements as needed!
    • Single Sign-On - Allow business customers to log in to many apps with one click using an existing Identity provider. If they want to bring their own corporate identities like federating with their Okta or Microsoft Azure AD accounts, we can quickly implement that by setting up the configurations in our admin console.
  • Outcome #4 - Reduced Support Costs

This comprehensive diagram breaks down our authentication sequence from left to right:

Scenario

Your end user uses any method to access the application from a client browser.

  1. They initiate an authentication request again e.g. SAML, OIDC, maybe OAuth2.
  2. They hit our Universal Login:
  • Hosted login page that is customizable with your own branding using settings in the Auth0 Dashboard or your own custom CSS, HTML.
  • Security features are built into the new Universal Login that allow you to detect anomalies and run risk assessments e.g. built-in bot detection, breached password detection, brute force protection, and suspicious IP throttling to name a few.
  • You can toggle specific features on and off from our administrative console without implementing it yourself. The legwork is offloaded to us, so you don’t have to manage that on your end.
  1. Once the user gets past Universal Login, the next steps depend on whether they’re registering or they’re authenticating. Check out some Actions that can be triggered pre- or post-registration:
  • Pre-registration Actions: You can deny a registration attempt based on some contextual information. If you’re collecting user information and you’re in healthcare, for example, you may need to verify their Social Security number or their Medicare number. To accomplish this, you’ll most likely have an integration with a third-party tool to verify that identity. We can collect that information through the form and pull it into the Action for continual reference. Using this context, you can make the call to the third-party tool for identity verification. Based on the response, you can then deny the user’s registration attempt or allow them to move forward.
  • Post-registration Actions: Typical use cases associated with this include some of our customers who like to write to their own databases to collect user information like emails. If they want to write to their CRM platforms for later references like potential marketing campaigns.
  1. Once the user successfully authenticates or registers, both an access and ID token are minted. You can further augment those JSON web tokens with any custom claims defined from within an Action or pulled from an external source.
  2. Operational Redirect Action is the ability to redirect the user from the authentication pipeline to an external page that either you can host, or perhaps a third-party page you have limited control over. After the user is redirected to that page, you may wish to gather additional information on them or guide them through reviewing terms and conditions. You can validate that through the verification process and then redirect back to the authentication pipeline so they can complete the authentication flow.
  3. Native multi-factor authentication. If your B2B customers are going to be federating or “SSO-ing” with their corporate identities, they may already be going through MFA from the upstream identity provider, so you may not have to worry about that. But, there are instances where the upstream IDP may not have MFA built-in and your customer requests that on your behalf. You have the flexibility to tailor that particular user experience accordingly, implementing MFA for some customers while allowing others to proceed without it. This is readily available through one of our templates within the Actions library.
  4. Finally, you’ll receive a modified access and ID token(s), which are sent to your application for consumption. You can send them in an API request as a bearer token so that you can validate it server side and provide access to a specific resource.

Demo

Now that you have a better understanding of our authentication sequence, let’s dive into the demo! Note: You might recognize a few names from a famous paper company :eyes:

Part 1

Set Up Organizations

Navigate to the Auth0 dashboard and go to the Activity page

Here, you can find your: daily active users, user retention rates, number of sign-ups, and failed login attempts. This is a glance at user activities as part of your tenant. A reminder, this will be specific to your tenant, and you can create as many tenants as you need. We have different environment tags that you can modify. If it’s in production and you want to switch it to development or staging, you can definitely do that as well.

Organizations can be representative of a tenant that you associate with a customer. Here, we’ll use Acme Corp., Atko, and Okta. You can think of them as different entities from a multi-tenancy perspective.

Acme Corp:

  • Basic branding
  • Customer logo
  • Choose specific colors
  • These bits of metadata associated with the brand can be incorporated into your application. If you want that passed from the JWT to your application so you can brand it for the instance of the application, you can do this as well.

Invite Members to Organizations

Let’s go ahead and invite Michael Scott (I’ve been rewatching the Superfan episodes of The Office. Definitely recommend it if you haven’t watched.)

I’m going to send an invite to michael.scott@atko.email with the dashboard administrator and organization administrator roles. These will determine what specifically I can do as a user or a member of a specific organization. In the context of Acme Corp, I’m both a dashboard administrator as well as an organization administrator. There are specific permissions associated with each of these roles and you’ll see that momentarily. I’m going to go ahead and send the invite.

It’s going to be pending. So I’ll navigate to my inbox, michael.scott@atko.email, and it’s there.

Let’s go ahead and accept the invitation. Now all I have to do to sign up is set a password.

I’m going to go ahead and set a password now. And you’ll see here, I receive a branded experience.

It’s Acme and it has the primary color here, so I’m going to go ahead and continue. I’m redirected back to the application with specific metadata associated with the organization in that context as well as the information for this specific user.

Understanding the Tokens

This is going to be the decoded ID token:

  • _org_display_name: That was defined in the organization with the administrative console.
  • _org_roles: These are the roles that were associated with this user in the context of this organization.
  • _member_of_orgs: An array of all of the orgs this user may belong to.
  • The rest is identifier information, and the last two are specific to the organization itself.

If I go to permissions, this is the access token that I’m granted. Typically I would use this in an API request as a bearer token in the authorization header. It does have specific information as it pertains to this user:

  • _client_id: the application that the user was authenticating against
  • _connection_id: the connection that I used. This is how I connected, or how I authenticated. This is the ID of that database connection that I’ve authenticated with. The rest of the attributes/claims are duplicated from the ID token.

  • Permissions: These permissions are going to be associated with the audience dashboard API as well as the dashboard administrator. Now your application can consume this information and then determine based on what is returned:
    • what the user should see
    • how they should move forward in your application
    • what services they may have access to

You can also do this on the backend as well. When you send the access token to your service, your service will be responsible for validating the access token itself. Validity of the token could mean whether it’s expired, whether it has the right permissions, scopes, etc.

Organization Management

I do have a step-up functionality here where based on the audience parameter or a scope requested, you can actually initiate a multi-factor authentication event. I’m going to do a Google authenticator or similar.

I’m going to go ahead and type in the 6-digit code and hit continue. We also have biometrics built in as well, so if you want to enable biometrics, the next time the user authenticates or goes through an authorization event, they may not necessarily need to type in their password from that point on. They can just use the biometrics enabled on that specific device. I’m using my laptop right now, so Touch ID is available, but Face ID would also be available if you were on a mobile device accessing a web browser.

I can manage and see the metadata associated with the organization itself. Acme Corp is the organization that I invited Michael Scott to as an organization administrator, and on the left, you can see the metadata associated with the organization. Behind the scenes, I’m just making an API call to our org endpoint. This will allow you to brand your applications specifically for the organization. So, I have two people as listed org members within Acme Corp.

So if I wanted to invite an additional user, I can do so here. Let’s invite dwight.schrute@atko.email.

Dwight is going to be a dashboard user. So these are all the different roles available within my tenant that I can incorporate and associate right within an organization. I predefined these, so it’s important to note that you can define as many roles as you require and you can incorporate them across all of your organizations as needed.

I’m going to do dashboard user > send an invite. If I go to organizations and refresh invitations, I should see that pending here as well. Should Dwight choose to accept the invitation, it will disappear and his user profile will be created.

Our APIs can be easily leveraged so that you can build your own interfaces, you don’t have to necessarily rely on the administrative console to do the invitations, to add your members, or to do any sort of customization work. You can offload that right to your customers, so they can manage their own organization details, invite their own members, delete members, and revoke permissions.

Part 2:

Let’s go back to Organizations. This time, let’s go ahead and add Michael Scott to our Atko organization.

Typically, if the user doesn’t already exist in your tenant you would go through the invitation route. I can invite the user again so that they can accept the invitation, but I’m actually just gonna go ahead and add the member because Michael Scott is already a user in my tenant.

I’m gonna go ahead and add members > michael.scott@atko.com. And then let’s go ahead and assign roles.

This time Michael should just be a dashboard user.

Let’s log in as Michael Scott again. This time you’ll notice that the experience is going to be a little bit different because now that Michael is part of two organizations, we do have an organization picker, so you can allow the user to pick and choose which organization context the user may want to authenticate into. In this case, Michael is going to be authenticating in the context of the Atko organization despite having membership in both, so I’m going to go ahead and hit Atko.

I’m brought back to the same application. Within the ID token, you’ll see that the metadata has changed.

  • _org_display_name: “Atko”
  • _org_roles: “dashboard user” Is reflective of the context that the user authenticated against.
  • _member_of_orgs array: I have 2 objects here: ACME Corp and Atko.
  • The rest is pretty much the same as the org metadata is reflective of the Atko organization.

Once I go to permissions, all of that will be updated as well. You can have the application consume this information as required, or again your service in the backend can also do the heavy lifting.

You’ll notice up here, I also have an org switching capability that I built into the platform. Since Michael Scott is part of both Acme Corp and Atko, ideally he should be able to switch organization context as needed without having to reauthenticate.

So, if I were to click on Acme Corp, you’ll see that the context should switch and now you’ll see the org display name changed.

Org management came back because, in this context, he is an organization administrator. Everything else pretty much remains the same up to this point.

If I hit org management, I am prompted for the MFA option again:

To properly implement organization context switching, you would make an authorization call again to Auth0, but this time you would pass the specific connection parameter associated with the organization ID of the organization you would want the user to switch to. The only prerequisite is that both of the organizations should share the same connection that was recently used to authenticate the user initially, in order for the SSO to work or the switching to work.

Now switching gears, if I log out and navigate to Actions within the admin console, a couple of Actions that I have defined here for login specifically are:

  • Add user roles to JWT
  • Add all users Organizations
  • Enable MFA

The first one is adding user roles to the JWT. Again, this speaks to the ability to augment your JSON web tokens. If you want to incorporate external information, if you want to pull metadata from the existing Auth0 profile, you can do that as well, back to the whole notion of the platform’s extensibility and flexibility.

Taking a look at the code snippet, you should be able to decipher that this bit of logic here is tied to an authentication event associated with an organization context. I am pulling the org display name from the event object, which returns all the metadata associated with the authentication event.

So if the user were to be authenticating in the context of an organization, I can pull this metadata here and then augment the access token, the ID token with this information. I can also add additional roles to the tokens as well, pulling that information either from Auth0 or an external source.

Now If I go back to Flows, one other thing I do want to show would be MFA, this is the “step up MFA” enabled. It’s based on a conditional statement here. It’s a little messy, but essentially I’m just checking whether or not the user is authenticating in the context of an organization. Is it an authorization event? And are they trying to administer organizations here? And then, I can just enable any multi-factor authentication option that is readily available in my tenant.

Finally, I do want to touch on our marketplace as I spoke to this earlier.

We have so many integrations that you can leverage, whether it’s log streaming, or Social Connections, all of that is within our marketplace and readily available. This speaks to our extensibility framework. If you want to augment the authentication experience, if it’s a requirement, if you need to go through an ID proofing process, or anything like that, you would most likely be able to find it here. You can always build your own with a custom Action as well. If there are APIs readily available, you can incorporate that, you can bring your own packages associated with NPM, and so forth.

Happy authenticating!

5 Likes

Good stuff @shreya.gupta ! :cowboy_hat_face: :tada:

2 Likes