Today I’ll wrap up my series on Azure Active Directory’s (Azure AD) integration with Google’s G-Suite. In my first entry I covered the single-sign on (SSO) integration and in my second and third posts I gave an overview of Google’s Cloud Platform (GCP) and demonstrated how to access a G-Suite domain’s resources through Google’s APIs. In this post I’m going to cover how Microsoft provides automated provisioning of user, groups, and contacts . If you haven’t read through my posts on Google’s API (part 1, part 2) take a read through so you’re more familiar with the concepts I’ll be covering throughout this post.
SSO using SAML or Open ID Connect is a common capability of most every cloud solutions these days. While that solves the authentication problem, the provisioning of users, groups, and other identity-relates objects remains a challenge largely due to the lack of widely accepted standards (SCIM has a ways to go folks). Vendors have a variety of workarounds including making LDAP calls back to a traditional on-premises directory (YUCK), supporting uploads of CSV files, or creating and updating identities in its local databases based upon the information contained in a SAML assertion or Open ID Connect id token. A growing number of vendors are exposing these capabilities via a web-based API. Google falls into this category and provides a robust selection of APIs to interact with its services from Gmail to resources within Google Cloud Platform, and yes even Google G-Suite.
If you’re a frequent user of Azure AD, you’ll have run into the automatic provisioning capabilities it brings to the table across a wide range of cloud services. In a previous series I covered its provisioning capabilities with Amazon Web Services. This is another use case where Microsoft leverages a third party’s robust API to simplify the identity management lifecycle.
In the SSO Quickstart Guide Microsoft provides for G-Suite it erroneously states:
“Google Apps supports auto provisioning, which is by default enabled. There is no action for you in this section. If a user doesn’t already exist in Google Apps Software, a new one is created when you attempt to access Google Apps Software.”
This simply isn’t true. While auto provisioning via the API can be done, it is a feature you need to code to and isn’t enabled by default. When you enable SSO to G-Suite and attempt to access it using an assertion containing the claim for a user that does not exist within a G-Suite domain you receive the error below.
This establishes what we already knew in that identities representing our users attempting SSO to G-Suite need to be created before the users can authenticate. Microsoft provides a Quickstart for auto provisioning into G-Suite. The document does a good job telling you were to click and giving some basic advice but really lacks in the detail into what’s happening in the background and describing how it works.
Let’s take a deeper look shall we?
If you haven’t already, add the Google Apps application from the Azure AD Application Gallery. Once the application is added navigate to the blade for the application and select the Provisioning page. Switch the provisioning mode from manual to automatic.
Right off the bat we see a big blue Authorize button which tells us that Microsoft is not using the service accounts pattern for accessing the Google API. Google’s recommendation is to use the service account pattern when accessing project-based data rather than user specific data. The argument can be made that G-Suite data doesn’t fall under project-based data and the service account credential doesn’t make sense. Additionally using a service account would require granting the account domain-wide delegation for the G-Suite domain allowing the account to impersonate any user in the G-Suite domain. Not really ideal, especially from an auditing perspective.
By using the Server-side Web Apps pattern a new user in G-Suite can be created and assigned as the “Azure AD account”. The downfall with of this means you’re stuck paying Google $10.00 a month for a non-human account. The price of good security practices I guess.
Microsoft documentation states that the account must be granted the Super Admin role. I found this surprising since you’re effectively giving the account god rights to your G-Suite domain. It got me wondering what authorization scopes is Microsoft asking for? Let’s break out Fiddler and walk through the process that kicks off after clicking on the Authorization button.
A new window pops up from Google requesting me to authenticate. Here Azure AD, acting as the OAuth client, has made an authorization request and has sent me along with the request over to the Google which is acting as the authorization server to authenticate, consent to the access, and take the next step in the authorization flow.
When I switch over to Fiddler I see a number of sessions have been captured. Opening the WebForms window of the first session to accounts.google.com a number of parameters that were passed to Google.
The first parameter gives us the three authorization scopes Azure AD is looking for. The admin.directory.group and admin.directory.user are scopes are both related to the Google Directory API, which makes sense if it wants to manage users and groups. The /m8/feeds scope grants it access to manage contacts via the Google Contacts API. This is an older API that uses XML instead of JSON to exchange information and looks like it has been/is being replaced by the Google People API.
Management of contacts via this API is where the requirement for an account in the Super Admin role originates. Google documentation states that management of domain shared contacts via the /m8/feeds API requires an administrator username and password for Google Apps. I couldn’t find any privilege in G-Suite which could be added to a custom Admin role that mentioned contacts. Given Google’s own documentation along the lack of an obvious privilege option, this may be a hard limitation of G-Suite. Too bad too because there are options for both Users and Groups. Either way, the request for this authorization scope drives the requirement for Super Admin for the account Azure AD will be using for delegated access.
The redirect_uri is the where Google sends the user after the authorization request is complete. The response_type tells us Azure AD and Google are using the OAuth authorization code grant type flow. The client_id is the unique identifier Google has assigned to Azure AD in whatever project Microsoft has it built in. The approval_prompt setting of force tells Google to display the consent window and the data Azure AD wants to access. Lastly, the access_type setting of offline allows Azure AD to access the APIs without the user being available to authenticate via a refresh token which will be issued along with the access token. Let’s pay attention to that one once the consent screen pops up.
I plug in valid super user credentials to my G-Suite domain and authenticate and receive the warning below. This indicates that Microsoft has been naughty and hasn’t had their application reviewed by Google. This was made a requirement back in July of 2017… so yeah… Microsoft maybe get on that?
To progress to the consent screen I hit the Advanced link in the lower left and opt to continue. The consent window then pops up.
Here I see that Microsoft has registered their application with a friendly name of azure.com. I’m also shown the scopes that the application wants to access which jive with the authorization scopes we saw in Fiddler. Remember that offline access Microsoft asked for? See it mentioned anywhere in this consent page that I’m delegating this access to Microsoft perpetually as long as they ask for a refresh token? This is one of my problems with OAuth and consent windows like this. It’s entirely too vague as to how long I’m granting the application access to my data or to do things as me. Expect to see this OAuth consent attacks continue to grow in in use moving forward. Why worry about compromising the user’s credentials when I can display a vague consent window and have them grant me access directly to their data? Totally safe.
Hopping back to the window, I click the Allow button and the consent window closes. Looking back at Fiddler I see that I received back an authorization code and posted it back to the reply_uri designated in the original authorization request.
Switching back to the browser window for the Azure Portal the screen updates and the Test Connection button becomes available. Clicking the button initiates a quick check where Azure AD obtains an access token for the scopes it requires unseen to the user. After the successful test I hit the Save button.
Switching to the browser window for the Google Admin Portal let’s take a look at the data that’s been updated for the user I used to authorize Microsoft its access. For that I select the user, go to the Security section and I now see that the Azure Active Directory service is authorized to the contacts, user, and group management scopes.
Switching back to the browser window for the Azure Portal I see some additional options are now available.
The mappings are really interesting and will look familiar to you if you’ve ever done anything with an identity management tool like Microsoft Identity Manager (MIM) or even Azure AD Sync. The user mappings for example show which attributes in Azure AD are used to populate the attributes in G-Suite.
The attributes that have the Delete button grayed out are required by Google in order to provision new user accounts in a G-Suite domain. The options available for deletion are additional data beyond what is required that Microsoft can populate on user accounts it provisions into G-Suite. Selecting the Show advanced options button, allow you to play with the schema Microsoft is using for G-Suite. What I found interesting about this schema is it doesn’t match the resource representation Google provides for the API. It would have been nice to match the two to make it more consumable, but they’re probably working off values used in the old Google Provisioning API or they don’t envision many people being nerdy enough to poke around the schema.
Next up I move toggle the provisioning status from Off to On and leave the Scope option set to sync only the assigned users and groups.
I then hit the Save button to save the new settings and after a minute my initial synchronization is successful. Now nothing was synchronized, but it shows the credentials correctly allowed Azure AD to hit my G-Suite domain over the appropriate APIs with the appropriate access.
So an empty synchronization works, how about one with a user? I created a new user named email@example.com with only the required attributes of display name and user principal name populated, assigned the new user to the Google Apps application and give Azure AD a night to run another sync. Earlier tonight I checked the provisioning summary and verified the sync grabbed the new user.
Review of the audit logs for the Google Apps application shows that the new user was exported around 11PM EST last night. If you’re curious the synch between Azure AD and G-Suite occurs about every 20 minutes.
Notice that the FamilyName and GivenName attributes are set to a period. I never set the first or last name attributes of the user in Azure AD, so both attributes are blank. If we bounce back to the attribute mapping and look at the attributes for Google Apps, we see that FamilyName and GivenName are both required meaning Azure AD had to populate them with something. Different schemas, different requirements.
Switching over to the Google Admin Console I see that the new user was successfully provisioned into G-Suite.
Pretty neat overall. Let’s take a look at what we learned:
- Azure AD supports single sign-on to G-Suite via SAML using a service provider-initiated flow where Azure AD acts as the identity provider and G-Suite acts as the service provider.
- A user object with a login id matching the user’s login id in Azure Active Directory must be created in G-Suite before single sign-on will work.
- Google provides a number of libraries for its API and the Google API Explorer should be used for experimentation with Google’s APIs.
- Google’s Directory API is used by Azure AD to provision users and groups into a G-Suite domain.
- Google’s Contacts API is used by Azure AD to provision contacts into a G-Suite domain.
- A user holding the Super Admin role in the G-Suite domain must be used to authorize Azure AD to perform provisioning activities. The Super Admin role is required due to the usage of the Google Contact API.
- Azure AD’s authorization request includes offline access using refresh tokens to request additional access tokens to ensure the sync process can be run on a regular basis without requiring re-authorization.
- Best practice is to dedicate a user account in your G-Suite domain to Azure AD.
- Azure AD uses the Server-side Web pattern for accessing Google’s APIs.
- The provisioning process will populate a period for any attribute that is required in G-Suite but does not have a value in the corresponding attribute in Azure AD.
- The provisioning process runs a sync every 20 minutes.
Even though my coding is horrendous, I absolutely loved experimenting with the Google API. It’s easy to realize why APIs are becoming so critical to a good solution. With the increased usage of a wide variety of products in a business, being able to plug and play applications is a must. The provisioning aspect Azure AD demonstrates here is a great example of the opportunities provided when critical functionality is exposed for programmatic access.
I hope you enjoyed the series, learned a bit more about both solutions, and got some insight into what’s going on behind the scenes.
thanks for this great tutorial. I was also playing around with user provisioning via Enterprise Applications in Azure AD and it works pretty nice. However, after I delete a user in Azure AD, it got only “suspended” in Google suite. Desired state would be deleted as well. Do you have any hints?
Hi Marco. It’s funny, I never actually played with the full lifecycle of the account. According to Google’s Directory API documentation, there is an API call that can be made to delete the user account. If I had to guess, Microsoft has instead chosen to make a change user API call to suspend the account rather deleting it.
If you think about suspend vs delete in the case of G-Suite it makes some sense. If Azure AD made a straight up delete call there wouldn’t be any corresponding orchestration to preserve the user’s data. By suspending the account the user is unable to login but the user’s data is preserved for the G-Suite admin to archive using whatever business process they may have in place.
Try to setup Single Sign On and provisioning myself for Azure AD and Google Suite. There is only one strange thing going on.
I can get SSO to work. I can get auto provisioning to work. But I can’t get them both the work at the same time. This results in error during Testing Google Connection while saving the provisioning settings. Even when test connection manually is working (before saving)
Any idea what can cause this problem?
My first setup was to have a separate super user with admin api priviledges in Google Suite. Had the impression that this was causing the issue because after setting up SSO this new admin user should also use this authentication path. So I used my admin account for Google (which bypasses the SSO, would be nice to know how I can also set this up for other accounts) but this does not solve the issue.
Interesting Johan. I ran into a similar issue when I was testing that I chalked up the functionality being down for a period of time.
After configuring SSO I was unable to get provisioning working. After a few days I tried again after deleting the App from my tenant and re-adding it and it worked for both SSO and Provisioning. Personally I found the provisioning piece kind of buggy.
I know there a few Microsoft lurkers out there maybe one of them can answer the question or help out? Otherwise I’d suggest dropping a post on the MS documentation page.
Either way, try deleting the app from the tenant and re-registering it if you haven’t already.
I also went through the issue with the provisioning credentials being accepted and then it would just show a blank screen and do nothing. Had tried on multiple computers/browsers/different ISP’s, same thing. I opened a ticket with MS as well and they said to delete and re-add which I didnt’ want to do. Through my own troubleshooting I found the following worked for me.
1. Turning off SSO
2. Configuring the account provisioning
3. Turn SSO back on.
– Clear your browser cache
– Close all browser windows
– Login to Azure AD (I used firefox)
– Go to your Enterprize applications
– DISABLE SSO
– Go into the account provisioning section
– Wait a few minutes (waited about 3-5 minutes)
– Configure the Auto Account provisioning
– Once confirmed its completed, SAVE
– Turn the provisioning mode to ON, click SAVE agian
– Go back and turn on SSO
– All the previous settings should auto-appear (including the existing cert) with only one field for the login URL to be re-entered
Hopefully this helps someone else. I spent a large chunk of time until I finally was able to get it going.
Thanks Hargo! This is great information
Great articles, I was able to get SSO working, however I am stuck on enabling auto provisioning from Azure. I’ve tried the steps Hargo mentioned above multiple times with multiple browsers (Chrome, Firefox, Edge) and from an AWS, have recreated the Azure App at least 3 times, disabled the PC firewall, connected to a mobile hotspot, the authorizing user is a super admin, I have also created and recreated multiple super admin accounts in Gsuite. When I click Authorize, it gets stuck on a page and says “Redirecting…”.
Inspecting the console, the message displayed is:
SecurityError: Permission denied to access property “oauthbuttonCallback” on cross-origin object
I had a lot of issues with the provisioning features as well James. I feel like the challenge is a common one where Microsoft is challenged with keeping up with Google’s API changes. It’s a common challenge everyone is faced with these days.
For your specific error, I’d try engaging Microsoft directly to see if they can offer some assistance.
Looping back to say I was able to resolve the issue with Microsoft support.
“C:\Program Files (x86)\Google\Chrome\Application\chrome.exe” –disable-web-security –user-data-dir=c:\my\data
This allowed the provisioning authorization to complete.
Side note, I’ve just moved into IT security, also in Boston, I feel like this blog is going to be a great resource for me. Thank you Matt for putting it all together!
Great to hear James and thanks for giving back to the community with the fix.
I recently took a new job with Amazon Web Services right down in the Seaport in Boston. We should grab lunch sometime.
Thanks James, I’ve been unable to fix this for months but this worked for me.. Worth mentioning that you need to close Chrome before running this, and for me it only worked in a command line.
Thanks for this great series! I love looking ‘behind the scenes’ on these types of things. 🙂
Quick question: I’m experiencing a problem with the mappings between Microsoft and G-Suite. Basically, the department field in Azure is not mapping correctly over to G-Suite, which I suspect has to do with an API change on Google’s side. Essentially, I am seeing the department value being set on the Organization name that is attached to the user account in G-Suite. I have not changed the default mappings so this behavior is happening ‘out of the box’.
You mentioned mappings in this article but I was wondering if you noticed any other odd behaviors when you were testing?
Great to hear you enjoyed the entry. As you can tell, I love pulling back the curtains as well.
The only weirdness I ran into was with the provisioning component seemingly failing for what seemed for no good reason. I expect it had to do with an API incompatibility as well. Keep in mind I only did the basics and didn’t get fancy.
I feel like the frequent changes to third party APIs is going to be the bane of any entity trying to play middle man like Microsoft is trying to do here. The more applications they onboard to the application gallery, the more overhead they have in keeping their integrations up to date.
Looking at the mappings is a good place to start to see what attribute they are trying to write to the G-Suite side. You could then check out the API documentation or use the Google API explorer to see if the attribute is still named the same.
Let me know what you find out.
Hello! I have the following problem: I can provision users, but the password is not taken to GSuite.
Do you have any idea what that is?
Hi there! Don’t quote me on this, but I don’t believe Azure AD supports any type of password synchronization to GSuite because the goal is for the credentials to stay in Azure AD and the user authenticate against Azure AD versus G Suite. Out of curiosity, what is the use case for requiring a password in G Suite after you’ve federated the authentication to Azure AD?
I am able to configure SSO with a non-admin g suite account, but when i try and sso with my g suite admin account i get the gsuite message “invalid email” in addition, in azure, when i try and configure provisioning, whenever i click save i get the error message,
We encountered an error while updating provisioning configuration for G Suite, every time, no matter what
Hi Dm. It’s been quite a while since I performed this integration, but it would be expected the admin account would not support SSO. After all if SSO broke, you’d have no mechanism to log into G Suite to fix it. 🙂
Another poster offered a solution to the provisioning error. Take a look through the earlier comments for it.
Nice articles related to AAD and G-Suite.
In our case we have multiple offices which all have their own domain in G-Suite with existing users (firstname.lastname@example.org, email@example.com)
We have decided that we are going to make the AAD the IDP and all the users will have a different account here, called, firstname.lastname@example.org, email@example.com. (This to give them all the same and 1 single Identity)
Do you think it is possible for John and Jane to logon with their “new” @azure domain account and get access to the apps/documents asociated with their already existing G-Suite account (@office1,2,3,4,5,etc)?
And this without creating accounts from the domain @azure in G-Suite.
I hope you understand my question 🙂
I’m thrilled you found it useful.
I think what you’re doing is completely viable, but you would need to test it to be sure. What I would suggest is populating the Google login name in an attribute in Azure AD (perhaps one of the customAttributes?). You would then modify the claims mappings for the G Suite Azure AD app to pass that attribute as the username. Give it a go and let me know!
Thanks for your reply! I have indeed been able to make it work using the customAttributes, I have added the Google login name in one of the attributes (Like you said) and set that attribute as the unique identifier.
Now I am going to try to provision a totally new user in G-suite from a new user created in AAD.
I want to:
1. Create the new user in AAD
2. Add the G-suite login name to the custom attribute
3. Enable provisioning and configure the attributes settings
I hope that this can automatically create a new user in G-suite within the domain of G-suite (so not the AAD domain).
Thanks and have a great day!
A message to keep you up to date and right away to ask a question 😀
So the provisioning configuration is working and we can now provision users from @azure to gsuite and login to any google app with the @azure domain account.
The only problem we see is that when using g-mail it sends the e-mail using the @azure account which is a O365 domain. O365 is the one receiving everything being send to the @azure account.
The question we are having now is, how can we configure the accounts in such a way, that when we send an e-mail from g-mail, it uses the @gsuite domain to send the e-mails? (we have got 2 domains, 1 azure domain and 1 g-suite domain).
Any hints or tips are welcome.
Any chance you could throw together a diagram of the architecture? It would help me to understood your intended flow. Feel free to send me a DM on Twitter if that is easier.
This post and your other post regarding g-suite provisioning were really helpful, thanks! I was wondering though if you could answer a quick question regarding OUs syncing with G-Suite. When a new user is created in AD, it also creates the user in G-suite since we have provisioning set up, however it places that user in the base G-suite OU rather than the one they are supposed to be in. For example in AD we would have “Users>TestUser>John.Doe”, but when that user is provisioned into G-suite, they do not go into the Users>TestUser OU. We’re a K-12 school district so each year we are creating hundreds of users that need to go into specific grade level groups. Thanks!
Hi Brett. Sorry for the massive delay in responding to your post. I’ve never performed the a sync directly from Windows AD to G-Suite. The use cases I experimented were from Azure AD to G-Suite and since Azure AD is a flat directory, I didn’t run into this. Hope you figured this out!
Thank you for this article. Would you be able to explain, or direct me to information on, how the integration works when the users already exist in G Suite? The scenario is that I currently have Email, Contacts and Calendars in G Suite, and want to use Office 365 Business for apps and onedrive for cloud file storage. I plan on handling user creation and management within Azure AD, but how would I attach existing G Suite users to AAD users created after the fact?
I haven’t done that scenario before. I’m about to shift to a new role that will be more MS focused. This is a use case I’ve been asked about a few times that I plan on testing.
Argh. I was afraid of getting that reply 😦 though I appreciate you taking the time to respond. I look forward to any update you may have. Thanks
Same here… I work in a schoolboard and they (the pedagogic team) created around 15 000 users in GSuite (out of 55 000…) mostly by importing CSV since Google’s solutions were not appropriate at the time we decided to use GSuite and our users were not in Azure AD at that time.
Now, I come across this solution and I realized it would have been cool if it existed 1+ year ago… Oh well 🙂
Any idea on what could happen if I enable the automatic provisioning with our existing Google users ? One thing I know and can confirm is that our “local” GSuite usernames match our Azure AD usernames. I was just wondering if they would wether merge or fail since they already exis on Google’s side…
Don’t know if anyone has some experience on this since it’s kind of hard for me to test as I am in production and we don’t even have SSO enabled yet… I am a bit concerned to enable all of this in a production environment even though I think I can select some specific groups to provision ?
You are right to not experiment with this in production! 😀
I’ve been asked this question a few times, but have never tested it. It would like depend on the API call being made from Azure AD. A quick glance at the API reference shows both an insert and update API call. If Azure AD is making an initial Insert API call, what happens is dependent on how G-Suite would handle creation of duplicate users. If it makes an Update call, the behavior would be different.
It’s definitely something I would not test in a production environment. Even if testing in a test environment panned out the way you wanted, there would still be risks. If you were interested in changing authorities from G Suite to Azure AD, exploring a migration path might be a safer bet.
Hi James , I have followed the steps and enabled Azure AD to be the SSO provider and enabled automated user provisioning and everything works well and user gets created in Google , but the user is automatically suspended on creation with a error message ” Unverified sign-in”. As per google users have to provide their phone number and activate their account on login. This is not a ideal user experience. Any Suggestion on why this is happening ? I already trusted the Azure AD app as well in API controls.