Support Google Cloud Identity in SCIM bridge
The SCIM bridge requested admin.directory.userschema.readonly during OAuth consent, which is a Google Workspace-only entitlement. Cloud Identity-only admins could not grant it, so the connect flow failed before any sync ran. The scope was also unused: the provider only calls Users.List, never the schemas, groups, or customers endpoints. Trim the requested scopes down to admin.directory.user.readonly so the integration works for Workspace and Cloud Identity (Free and Premium) tenants. Switch Users.List to projection=full so standard extended fields (Organizations, ExternalIds, Relations, Languages) are populated on synced users; full projection does not require any extra OAuth scope. Relabel the connector UI to "Google Workspace / Cloud Identity" to reflect the broader support. Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -135,7 +135,7 @@ export function GoogleWorkspaceConnector(props: {
|
||||
}
|
||||
toast({
|
||||
title: __("Success"),
|
||||
description: __("Google Workspace disconnected successfully"),
|
||||
description: __("Google Workspace / Cloud Identity disconnected successfully"),
|
||||
variant: "success",
|
||||
});
|
||||
dialogRef.current?.close();
|
||||
@@ -208,10 +208,10 @@ export function GoogleWorkspaceConnector(props: {
|
||||
<Google className="w-6 h-6" />
|
||||
</div>
|
||||
<div className="mr-auto">
|
||||
<h3 className="font-medium">{__("Google Workspace")}</h3>
|
||||
<h3 className="font-medium">{__("Google Workspace / Cloud Identity")}</h3>
|
||||
<p className="text-sm text-txt-secondary">
|
||||
{__(
|
||||
"Connect Google Workspace to automatically sync users via SCIM.",
|
||||
"Connect Google Workspace or Google Cloud Identity to automatically sync users via SCIM.",
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -229,7 +229,7 @@ export function GoogleWorkspaceConnector(props: {
|
||||
<Google className="w-6 h-6" />
|
||||
</div>
|
||||
<div className="mr-auto">
|
||||
<h3 className="font-medium">{__("Google Workspace")}</h3>
|
||||
<h3 className="font-medium">{__("Google Workspace / Cloud Identity")}</h3>
|
||||
<p className="text-sm text-txt-secondary">
|
||||
{sprintf(__("Connected on %s"), dateTimeFormat(connector.createdAt))}
|
||||
</p>
|
||||
@@ -245,7 +245,7 @@ export function GoogleWorkspaceConnector(props: {
|
||||
{__("Settings")}
|
||||
</Button>
|
||||
)}
|
||||
title={__("Google Workspace Settings")}
|
||||
title={__("Google Workspace / Cloud Identity Settings")}
|
||||
className="max-w-lg"
|
||||
>
|
||||
<DialogContent padded className="space-y-6">
|
||||
@@ -253,7 +253,7 @@ export function GoogleWorkspaceConnector(props: {
|
||||
<div>
|
||||
<h4 className="text-sm font-medium">{__("Excluded user names")}</h4>
|
||||
<p className="text-sm text-txt-secondary mt-1">
|
||||
{__("Users with these user names will not be synced from Google Workspace.")}
|
||||
{__("Users with these user names will not be synced from Google Workspace / Cloud Identity.")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
@@ -298,7 +298,7 @@ export function GoogleWorkspaceConnector(props: {
|
||||
|
||||
{currentExcludedUserNames.length === 0 && (
|
||||
<p className="text-sm text-txt-secondary text-center py-4">
|
||||
{__("No excluded user names. All Google Workspace users will be synced.")}
|
||||
{__("No excluded user names. All Google Workspace / Cloud Identity users will be synced.")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -311,13 +311,13 @@ export function GoogleWorkspaceConnector(props: {
|
||||
{__("Disconnect")}
|
||||
</Button>
|
||||
)}
|
||||
title={__("Disconnect Google Workspace")}
|
||||
title={__("Disconnect Google Workspace / Cloud Identity")}
|
||||
className="max-w-lg"
|
||||
>
|
||||
<DialogContent padded className="space-y-4">
|
||||
<p className="text-txt-secondary text-sm">
|
||||
{__(
|
||||
"This will disconnect your Google Workspace integration. Users will no longer be automatically synced via SCIM.",
|
||||
"This will disconnect your Google Workspace / Cloud Identity integration. Users will no longer be automatically synced via SCIM.",
|
||||
)}
|
||||
</p>
|
||||
<p className="text-red-600 text-sm font-medium">
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
package googleworkspace
|
||||
|
||||
var (
|
||||
// OAuth2Scopes are the Google Workspace OAuth2 scopes required by the
|
||||
// SCIM provisioning bridge. The bridge reads users, user schemas, group
|
||||
// members, and customer info from the Admin Directory API.
|
||||
// OAuth2Scopes are the OAuth2 scopes required by the SCIM provisioning
|
||||
// bridge to read users from the Admin Directory API. The scopes are
|
||||
// intentionally limited to what the bridge actually consumes so the
|
||||
// integration also works for Google Cloud Identity (Free or Premium)
|
||||
// customers, not only Google Workspace customers. In particular,
|
||||
// admin.directory.userschema is a Workspace-only entitlement (custom
|
||||
// user fields are not available on Cloud Identity) and must not be
|
||||
// requested here, otherwise Cloud Identity-only admins cannot complete
|
||||
// the OAuth consent flow.
|
||||
OAuth2Scopes = []string{
|
||||
"https://www.googleapis.com/auth/admin.directory.user.readonly",
|
||||
"https://www.googleapis.com/auth/admin.directory.userschema.readonly",
|
||||
"https://www.googleapis.com/auth/admin.directory.group.member.readonly",
|
||||
"https://www.googleapis.com/auth/admin.directory.customer.readonly",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -68,7 +68,11 @@ func (p *Provider) ListUsers(ctx context.Context) (scimclient.Users, error) {
|
||||
pageToken := ""
|
||||
|
||||
for {
|
||||
call := adminService.Users.List().Customer("my_customer").MaxResults(500).Context(ctx)
|
||||
call := adminService.Users.List().
|
||||
Customer("my_customer").
|
||||
MaxResults(500).
|
||||
Projection("full").
|
||||
Context(ctx)
|
||||
if pageToken != "" {
|
||||
call = call.PageToken(pageToken)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user