One of the client projects I work on has larger, enterprise customers. Because of this, I needed to create a way for their users to sign into our application using single sign-on (SSO). To do that, we needed to automatically provision users in our system.
This is something I wasn’t familiar with before, so I embarked on a bit of research. Here’s the summary of my findings on implementing SSO using a variety of approaches for Google Workspace (formerly GSuite).
OAuth and SAML
There are two key technologies used for SSO, OAuth and SAML. I found an excellent resource comparing the two. OAuth is primarily used by social media sites to allow authentication while keeping credentials secure.
OAuth was developed after SAML, which is focused on more control. SAML allows enterprises to better manage and share login information which is why in an enterprise environment you’ll often see SAML as the de facto protocol.
For single sign-on, we could use either OAuth or SAML 2.0, depending on the specific requirements. I never wrote an SSO integration over SAML, so I jotted down my thoughts on possible solutions.
Laravel Socialite for SSO
For the most basic option, we could use Laravel Socialite’s Google provider (OAuth) to allow sign-in for domains previously whitelisted by organizational admins.
This would basically be “Sign in with Google” for whitelisted/configured domains only. This solution feels uncertain for me, because somehow it doesn’t feel “proper.” My feelings are a bit vague here, though, and I can’t put my finger on exactly why I have doubts.
Although this approach allows sign-in and JIT (just-in-time) user provisioning, the user data could get out of sync. Even if we sync whenever a user reauthenticates, this does not allow for user deprovisioning from the client’s system unless the person has tried to log in with revoked credentials.
For instance, when the user is removed from Google Workspace, how would our system be notified? It wouldn’t, which would cause a problem in our specific domain. If a user is removed from the enterprise system, we need to be notified to revoke their access.
User provisioning via SAML and SSO
A more advanced option is SAML which is well known for consuming Identity Providers (IdP; such as one provided by Google) from Service Providers (our project).
In fact, one of my colleagues, Peter, has worked on a team that has integrated authentication over SAML for the European Commission. As a result, we had a pretty reliable estimate it would take days (not weeks) to add SSO using SAML.
The Google Workspace admin has a catalog of SAML connectors we can choose from. In our case, we’d need to implement a custom SAML app in Google Workspace.
The initial configuration may feel a bit convoluted, but we assume Google Workspace admins are not noobs and copy/pasting a few URLs for configuration is not a big deal.
Once the admin configures the SAML integration, users would be able to sign into the project using Google IdP. In fact, there’s a thin Laravel package that makes SAML integration easy. It’s not really maintained (latest release in 2019), but it’s a thin wrapper only and it’s proven to work with Laravel 8.
The downside of this solution though is that, again, we would only do JIT user deprovisioning upon receiving a non-successful auth response. I’m not sold on using a non-successful auth response for user deprovisioning — it’s just not explicit enough. There could be another intermittent problem causing auth to fail and then the system incorrectly deprovisions the user. Messy.
Using Cloud Identity and SAML
Google has a service called Cloud Identity. It’s not part of Google Workspace, but you can decide to use it and create accounts in Cloud Identity for your Google Workspace users. Then, you can use Cloud Identity for SSO, after you have configured SAML.
The upside of this is that Cloud Identity supports automatic user provisioning and deprovisioning for a set of apps from a catalog. I couldn’t find how to write a custom connector though, even though they mention it is possible.
If the automated provisioning connector you need isn’t in the catalog, work with your service provider to develop the connector.
The tradeoff is minimal documentation for custom integrations with Cloud Identity. It’s also a paid option, $6/mo per user. We don’t want to assume our Google Workspace customers would always use Cloud Identity and it adds a cost overhead to the service we are providing.
Google Workspace API and programmatic user provisioning
I was initially thinking of on-demand or a scheduled sync that would retrieve Google Workspace users from an organization’s admin account, but I found a better option.
The Google Workspace admin could authorize access to the following endpoint (with the appropriate scopes):
https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/watch. We can then register webhooks to receive push notifications whenever a user’s resource changes for a given domain.
To put it together:
- The Google Workspace admin would configure the integration by authorizing access to Google Workspace API endpoint.
- We would make an initial fetch of users and provision them automatically.
- We would immediately register webhooks to receive notifications whenever a user is created, updated, or deleted.
This is clearly more development than using a simple solution like Socialite, but it feels like the most robust way to go. I would expect this would take a week or so for a pair of senior developers to implement.
In the end, we prioritized other work but I suspect we’ll return to this later in the year. I’d love to hear if you have a better idea on how to solve this problem.