3 Approaches to Add Enterprise SSO to Your App
Architecting SSO from a Systems Design perspective: what code and data lives where, who controls what, and what this ultimately means for your business as you grow your app
More SaaS apps every day are crossing the enterprise chasm and selling their software to big companies. To do so, they must cross a gauntlet of every kind of buzzword compliance, usually beginning with implementing Single Sign-On (SSO).
Luckily, for developers, lots of solutions — like WorkOS — have emerged to make adding SSO easier. But not all of these shortcuts are created equally. They’re vastly different in how they’re architected and which responsibilities are handled by an API platform instead of your app. For you, this translates into big differences in the costs to migrate to and maintain these integrations.
We’ve covered an overview of SSO before, but in this article, we’ll focus on it from the angle of systems design: what code and data lives where, who controls what, and what this ultimately means for your business as you grow your app.
There’s three approaches you can take to adding enterprise SSO to an existing app:
A. Direct Integration
One way to approach enterprise SSO is to integrate manually with the identity providers your first few enterprise customers are using: companies like Okta, OneLogin, Microsoft Azure Active Directory, Salesforce, and GSuite (which can act as an identity provider for other apps). Direct integration is essentially cooking up your own IdP integrations, each with a distinct recipe that you’ll need to learn and master.
This first means keeping track of which of these providers each of your customers is using, building out integrations for each, and adding logic to redirect the user to the appropriate identity provider flow based on which organization their account is part of.
You’ll also need to build integrations for each provider you choose to support. Though identity providers have coalesced around standards like SAML and OpenID Connect, every provider’s implementation of these standards has its own quirks. The major providers do offer their own well-documented SDKs that abstract away some of these details, but then again, this still means adding, updating, and debugging a dozen SDKs for each platform.
Taking this route must be done carefully to avoid security vulnerabilities, particularly with SAML. Security holes with SAML are routinely found in everything from individual apps, to open source libraries, to the identity providers’ own products.
Configuration can also take a lot of time, between setting up each enterprise customer with the right IdP, migrating users from normal accounts to SSO-backed accounts, or migrating customers between IdPs. You’ll spend a lot of time configuring certificates and figuring out how to map the user profile fields in your app to each provider (and each customer).
And when you’re done with all the SSO integrations, remember that SSO is just the beginning: all it does is let a user sign in. Many customers will also want directory sync integration (so that users can be provisioned and deprovisioned). And that’s a whole other kettle of fish.
- Offers maximum control over every detail of the integration.
- Expensive to maintain many different integrations with different service providers.
- Custom implementations must take extra care to avoid opening security holes.
B. All-In-One Middleware
There’s also a class of solutions on the market that are meant to solve all your authentication and identity needs, whether they be consumer or enterprise. They provide everything needed for login at every layer, at the UI, business logic, and data layer. These components are typically tightly coupled and must be adopted together. All-in-one middleware gives you the ‘prix fixe’ meal.
Auth0 has emerged as the pre-eminent solution in this category, but major cloud providers have also launched their own competitors in the space, including AWS Cognito and Google Cloud Identity Platform (formerly Firebase). There are a few facets in common to all of these worth examining:
1. THEY STORE AND AUTHENTICATE BOTH CONSUMER AND ENTERPRISE ACCOUNTS:
One fundamental limitation for these solutions to work is that they must be at the choke point for all authentication happening in your app, not just authentication for your enterprise customers. That means, before you can try their enterprise features, you’ve got to move all your existing users over first.
How does that work? All solutions in this category offer ways to bulk-import users via CSV and other formats, both with GUIs and via API. This can also be done incrementally: with each login, they can connect out to your database to check if there is a legacy account and, if so, migrate that user’s credentials to their data store.
- Rich Consumer Login Feature Set: Even if you’re only interested initially in using these solutions for enterprise Single Sign-On, they also offer a pretty comprehensive set of consumer login features that might be on your roadmap anyway. This includes social login, 2-factor authentication, and security features like Captchas and rate limiting. They also manage lifecycle emails (confirmation, welcome, reset password) on your behalf and can even do things like phone number-based authentication, handling SMSes for you.
- For AWS/Google, Synergies with Other Cloud Services: AWS Cognito has an ability to use its authentication in conjunction with specific cloud resources you might have set up, like S3 buckets or DyanmoDB databases. Its lifecycle emails use Amazon SES, which is convenient if you’re an AWS customer and inconvenient if not. Both integrate well with solutions these providers have built to synchronize user data between multiple clients (Firebase and AWS AppSync), which could be a major draw if you’ve already built your service around these.
- Migrating Accounts In and Out: If all you want to do is serve your first few enterprise customers, picking one of these means migrating all your user accounts over to them. Migrating accounts out can be harder than migrating them in (because why would they want you to migrate out?). It also means replacing the hardened and tailored code handling your non-enterprise accounts with a third party which brings risks. (more on this below in “Business Logic”).
- Enterprise Costs for Non-Enterprise Users: Every non-enterprise user who enters your app — even if they’re just trial accounts — costs money and could even bump you into another pricing tier. If you’re just getting started and enterprise SSO users represent a small portion of users, or if you rely on the familiar SaaS strategy of using self-serve consumer accounts as a “top of funnel” for your service to gain traction in companies before eventually converting to enterprise plans, this cost could add up!
- Limited Flexibility: While these solutions’ versions of some of these non-enterprise login features are battle-tested across thousands of apps, they can also be inflexible and prone to issues. If a social login provider breaks, you have to wait for them to fix it. If you want to change something about the way any of these features work, you’d better hope you’re an important enough customer for them to prioritize you.
2. THEY TAKE OVER ALL ACCOUNT-RELATED BUSINESS LOGIC
As your app grows, there are probably lots of bits of custom logic added over time around users and accounts: dealing with tiers, with trial periods, with group/team membership, or even calling out to other services like analytics and marketing apps when key user events occur. As you sell to enterprises, this sort of logic may grow still more convoluted as you must deal with customers converting from normal to enterprise plans.
The all-in-one middleware solutions are built to handle all business logic around accounts for you. That means their code is the first responder to anything account-related. This lets them abstract away a lot of details like which IdPs are being used and associating single accounts with multiple identities, which saves time. But this comes at a cost: all custom logic around user accounts in your app has needs to be ported over to run inside their environment — even logic that has nothing to do with enterprise users.
How do these solutions accommodate this?
- Auth0 allows what they call Actions, Rules, and Hooks — extension points where you can write your own code to run in a secure JS sandbox.
- AWS Cognito, naturally, lets you set up AWS Lambda functions as “triggers” to handle a good number of different events.
- Google Cloud Identity Platform is the weakest of the bunch in this category, currently only allowing the developer to add Cloud Functions to run on creation and deletion of accounts.
- Saves you from implementing a few tricky bits of logic juggling multiple sources of authentication and identity.
- Calling Back Into Your App From Outside: If any of the logic you port over has branches that depend on information only available in the app’s environment — or if actions implemented there need to be triggered — you may need to find a way to do that from outside. This could mean connecting to the app’s database or building new private APIs for this external code to “phone home” to, which could carry security implications.
- Maintaining Code In Someone Else’s Environment: The logic you port over won’t live with the rest of your code or be versioned in the same SCM system. This means extra consideration to include this code in any sort of review or audit process. Logs go to a different place than the logs from the rest of your code. It also can’t be unit tested in the same way as the rest of the app — you may need to find a way to “mock” the custom logic you’ve ported over to run in the middleware environment.
3. THEY RUN YOUR LOGIN AND SIGNUP UI
All of these solutions offer a turn-key login and signup UI you can drop into your app which, in most cases, is tightly coupled to the rest of the solution.
The all-in-one solutions differ in how they factor their UI and what customization options are offered:
- Auth0 gives developers a “Universal Login” UI. It has limited customization points: logo, title, colors, and ability to replace and localize some strings in the UI. Other than this, every app has the same cookie-cutter UI with the same “log in” and “sign up” tabs, which might not suit every app, particularly if you want to make these the same, or have a more tailored sign up funnel. As of writing, Auth0 is addressing some of these limitations by introducing a “New” flow which, among other things, allows some customization of page templates, but it is not yet at feature parity with the “classic” flow.
- AWS Cognito offers a login UI via the AWS Amplify framework which is tightly coupled to authentication. Customization opportunities are limited: you can upload a logo and customize the CSS used on pages.
- Google Cloud Identity Platform’s UI layer is well-factored and offers two choices: either a pre-built UI via the FirebaseUI SDK, or the lower-level Firebase Authentication SDK which allows the developer to build the UI themselves and call out to Google.
- If you’re starting from a bare bones login experience or one based on what came with the web framework you’re using, the pre-built UIs coupled with these solutions can offer features and affordances you’ll eventually need to build anyway.
- Migrating account UI takes time: Even if the customization options offered by these solutions end up sufficing, migrating to them is a major commitment that may require major restructure of your code, both on clients and server. You may even need to find a way to support both systems while your users update their client apps to new versions.
- Ceding control over fundamental part of user journey could hurt your funnel: While authentication is a reasonable thing for a SaaS business to outsource, your marketing, sign-up, and onboarding is not. Your core competency is figuring out the right way to reach customers in your vertical and convert them into paying users; the signup, login, and onboarding experience are key parts of that journey. Why accept anything less than full control here?
C. WorkOS SSO
WorkOS has taken a different approach to bring together the best of both worlds. You get access to the SSO buffet, with lots of pre-built IdP integrations but with the freedom to mix and match gastronomic (ahem, architectural) choices as you want.
Like the all-in-one solutions, WorkOS SSO saves the hassle of building, maintaining, and debugging a dozen different identity provider integrations and dealing with their idiosyncrasies and inconsistencies.
But like direct integration, with WorkOS, you maintain a high degree of control by keeping your existing UI, logic, and storage layers. You don’t need to change anything about the way you handle your non-enterprise users.
How it works:
- Setting Up Enterprise Users: Connections to your customers’ IdPs can be set up via API, via the developer dashboard, or even via a white-label Admin Portal you can give to your customers’ IT admins to save time. WorkOS supports every major identity provider.
- Authenticating Users: Whenever an enterprise user needs to sign in, all you need to do is redirect into WorkOS, passing their domain (that’s how WorkOS can look up the connection information and figure out how to talk to the customer’s IdP). WorkOS will deal with the rest and redirect back to the URL of your choice when finished, passing back the profile of the authenticated enterprise user. Just two places to integrate; that’s it!
The WorkOS Philosophy: There are also a couple things worth emphasizing about WorkOS’s product philosophy:
Enterprise-Focused, Not Identity-Focused: While the all-in-one solutions cover every type of identity and authentication need you could ever have, WorkOS is focused on adding features enterprises want to your app (identity being only one category). Supporting SSO is just the beginning of what enterprise customers want; WorkOS offers lots of other features you’ll need like directory sync, audit trails, and more.
Modularity: Every WorkOS product, including SSO, is built in a completely modular and loosely-coupled way, so you can mix and match and only integrate and pay for the features your customers need without overhauling large parts of your app.
- Simple integration: Once your enterprise users’ connections are set up, all you need is redirect into WorkOS and be set up to receive the authenticated user when you’re done.
- White Label Admin GUI: WorkOS gives you an easy way for your enterprise customers to configure and test their own connections. The other solutions require manual setup and back-and-forth that will eat up lots of engineering time for every new customer.
- Low Lock-In: You get to choose your user management solution. WorkOS doesn’t try to store all your user accounts. There’s no migration of user records in or out.
- Need to distinguish enterprise and non-enterprise users: Because WorkOS doesn’t run your entire login experience, there is one small hurdle to clear: You’ll need to add a little bit of extra logic so that your app knows when to treat a user as an enterprise user and invoke WorkOS. If you’re curious what this might entail, be sure to read our blog about best practices for this.