Clojure wrapper for the Google Cloud Identity Groups API (v1).
Provides idiomatic Clojure functions for the modern Cloud Identity Groups surface — group CRUD plus membership CRUD, lookup, search, and transitive-membership traversal. This is Google's strategic forward path for groups; the older Directory API (goog.workspace.admin) remains for backward compatibility.
Auth: use csl/scoped-delegated-credentials with the appropriate scope and a super-admin impersonation target:
All list / search functions return {:data [...] :next-page-token "..."}. :next-page-token is absent when there are no further pages.
SCOPE NOTE — when to use this vs. the Directory API (goog.workspace.admin):
GROUP IDENTITY FORMAT Resource names use Cloud Identity's structured form: "groups/{groupId}" for groups and "groups/{groupId}/memberships/{membershipId}" for memberships. To resolve a group by email or by external id, use lookup-group. The :parent for create-group is the customer name (e.g. "customers/C012345") — passed inside the body, not as a positional arg, because create-group lives on the top-level /v1/groups endpoint.
LRO POLLING Several mutations (create-group, update-group, delete-group, create-membership, delete-membership, get-membership-graph) return a long-running Operation. Most operations report :done true immediately; the response field carries the resulting resource. Cloud Identity v1 does NOT expose an operations.get endpoint — there is no wait-for-operation in this library. For the rare slow case (large dynamic group materialization), poll the resource itself via get-group or get-membership.
CLASS COLLISIONS
Group, Membership, Operation, Status model classes are
intentionally NOT imported. Typed bodies are constructed via JSON
round-trip; responses are read via csl/->clj (java.util.Map walking).
Typed sub-types under Group/Membership (DynamicGroupMetadata,
PosixGroup, MembershipRole, ExpiryDetail, EntityKey, GroupRelation,
RestrictionEvaluations) are populated transparently by the round-trip.
All functions return {:data ...} on success or {:error ...} on failure.
Clojure wrapper for the Google Cloud Identity Groups API (v1).
Provides idiomatic Clojure functions for the modern Cloud Identity
Groups surface — group CRUD plus membership CRUD, lookup, search, and
transitive-membership traversal. This is Google's strategic forward
path for groups; the older Directory API (goog.workspace.admin)
remains for backward compatibility.
Auth: use csl/scoped-delegated-credentials with the appropriate scope
and a super-admin impersonation target:
- CloudIdentityScopes/CLOUD_IDENTITY_GROUPS (read + write)
- CloudIdentityScopes/CLOUD_IDENTITY_GROUPS_READONLY (read-only)
All list / search functions return {:data [...] :next-page-token "..."}.
:next-page-token is absent when there are no further pages.
SCOPE NOTE — when to use this vs. the Directory API (goog.workspace.admin):
- Directory's Groups is the legacy CRUD surface; supports the broad
base of existing Workspace integrations.
- Cloud Identity's Groups is the modern surface with richer features:
dynamic groups (query-driven membership via :dynamic-group-metadata),
security labels (via :labels), additional group keys (alternate
identifiers), and the transitive-membership query family.
- Both libraries operate on the same underlying groups; the choice is
about which feature set the consumer needs. We document the parallel;
we do NOT build an adapter layer between the two.
GROUP IDENTITY FORMAT
Resource names use Cloud Identity's structured form: "groups/{groupId}"
for groups and "groups/{groupId}/memberships/{membershipId}" for
memberships. To resolve a group by email or by external id, use
lookup-group. The :parent for create-group is the customer name
(e.g. "customers/C012345") — passed inside the body, not as a
positional arg, because create-group lives on the top-level
/v1/groups endpoint.
LRO POLLING
Several mutations (create-group, update-group, delete-group,
create-membership, delete-membership, get-membership-graph) return a
long-running Operation. Most operations report :done true immediately;
the response field carries the resulting resource. Cloud Identity v1
does NOT expose an operations.get endpoint — there is no
wait-for-operation in this library. For the rare slow case (large
dynamic group materialization), poll the resource itself via get-group
or get-membership.
CLASS COLLISIONS
`Group`, `Membership`, `Operation`, `Status` model classes are
intentionally NOT imported. Typed bodies are constructed via JSON
round-trip; responses are read via csl/->clj (java.util.Map walking).
Typed sub-types under Group/Membership (DynamicGroupMetadata,
PosixGroup, MembershipRole, ExpiryDetail, EntityKey, GroupRelation,
RestrictionEvaluations) are populated transparently by the round-trip.
All functions return {:data ...} on success or {:error ...} on failure.(check-transitive-membership client parent & [opts])Check whether a member belongs to a group transitively (directly or through nested groups). Returns {:data {:has-membership <bool>}}.
parent is the group's resource name ("groups/{groupId}"). The
SDK appends "/memberships:checkTransitiveMembership" to form the
URL and rejects anything matching ^groups/[^/]+$ failing — i.e. pass
"groups/abc", not "groups/abc/memberships".
opts:
Check whether a member belongs to a group transitively (directly or
through nested groups). Returns {:data {:has-membership <bool>}}.
`parent` is the group's resource name ("groups/{groupId}"). The
SDK appends "/memberships:checkTransitiveMembership" to form the
URL and rejects anything matching ^groups/[^/]+$ failing — i.e. pass
"groups/abc", not "groups/abc/memberships".
opts:
- :query — REQUIRED; CEL expression naming the member to check,
e.g. "member_key_id == 'alice@example.com'"
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(cloudidentity-client credentials)(cloudidentity-client credentials opts)Build an authenticated Cloud Identity client.
credentials — a com.google.auth.oauth2.GoogleCredentials instance, typically from csl/scoped-delegated-credentials with a super-admin impersonation target. Must hold a CloudIdentityScopes/CLOUD_IDENTITY_GROUPS variant; calls fail at the API otherwise.
opts (optional):
Per-request opts on individual call sites override the client-level defaults.
Build an authenticated Cloud Identity client. credentials — a com.google.auth.oauth2.GoogleCredentials instance, typically from csl/scoped-delegated-credentials with a super-admin impersonation target. Must hold a CloudIdentityScopes/CLOUD_IDENTITY_GROUPS variant; calls fail at the API otherwise. opts (optional): - :read-timeout-ms per-client default read timeout (default 120000 / 120s) - :connect-timeout-ms per-client default connect timeout (default 30000 / 30s) Per-request opts on individual call sites override the client-level defaults.
(create-group client group & [opts])Create a new group. Returns an Operation. In the typical fast path the returned Operation has :done true with the new Group on :response; slower cases must poll the group via get-group (Cloud Identity v1 does not expose an operations.get endpoint).
group is a Clojure map with kebab-case keys, minimally:
:parent — the customer resource name ("customers/C012345")
:group-key — {:id "<email-or-external-id>"}
:display-name — human-readable name
:description — optional description
:labels — map of label keys to (typically empty) string values
(e.g. {"cloudidentity.googleapis.com/groups.discussion_forum" ""}
is required for a discussion group)
opts:
Create a new group. Returns an Operation. In the typical fast path the
returned Operation has :done true with the new Group on :response;
slower cases must poll the group via get-group (Cloud Identity v1
does not expose an operations.get endpoint).
`group` is a Clojure map with kebab-case keys, minimally:
:parent — the customer resource name ("customers/C012345")
:group-key — {:id "<email-or-external-id>"}
:display-name — human-readable name
:description — optional description
:labels — map of label keys to (typically empty) string values
(e.g. {"cloudidentity.googleapis.com/groups.discussion_forum" ""}
is required for a discussion group)
opts:
- :initial-group-config — :empty (default) or :with-initial-owner
(the latter adds the creator as an owner)
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(create-membership client parent membership & [opts])Create a new membership in a group. Returns an Operation (typically already :done true with the new Membership on :response).
parent — the group's resource name ("groups/{groupId}").
membership — a Clojure map with kebab-case keys, minimally:
:preferred-member-key — {:id "<email-or-external-id>"
:namespace "identitysources/IS_xyz" ;; for external
}
:roles — vector of role maps:
[{:name "MEMBER"}] (always required)
[{:name "MEMBER"} {:name "OWNER"}]
[{:name "MEMBER"
:expiry-detail {:expire-time "2026-12-31T00:00:00Z"}}]
opts:
Create a new membership in a group. Returns an Operation (typically
already :done true with the new Membership on :response).
`parent` — the group's resource name ("groups/{groupId}").
`membership` — a Clojure map with kebab-case keys, minimally:
:preferred-member-key — {:id "<email-or-external-id>"
:namespace "identitysources/IS_xyz" ;; for external
}
:roles — vector of role maps:
[{:name "MEMBER"}] (always required)
[{:name "MEMBER"} {:name "OWNER"}]
[{:name "MEMBER"
:expiry-detail {:expire-time "2026-12-31T00:00:00Z"}}]
opts:
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(delete-group client group-name & [opts])Delete a group (LRO). Returns an Operation; see create-group for polling semantics.
group-name is the resource name ("groups/{groupId}").
opts:
Delete a group (LRO). Returns an Operation; see create-group for polling
semantics.
`group-name` is the resource name ("groups/{groupId}").
opts:
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(delete-membership client membership-name & [opts])Delete a membership (LRO). Returns an Operation (typically already :done true).
membership-name is the resource name
("groups/{groupId}/memberships/{membershipId}").
opts:
Delete a membership (LRO). Returns an Operation (typically already
:done true).
`membership-name` is the resource name
("groups/{groupId}/memberships/{membershipId}").
opts:
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(get-group client group-name & [opts])Get a group by its resource name ("groups/{groupId}"). To resolve a group from an email or external id, use lookup-group first.
opts:
Get a group by its resource name ("groups/{groupId}"). To resolve
a group from an email or external id, use lookup-group first.
opts:
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(get-membership client membership-name & [opts])Get a membership by resource name ("groups/{groupId}/memberships/{membershipId}").
To resolve a membership from a member email or external id, use lookup-membership first.
opts:
Get a membership by resource name
("groups/{groupId}/memberships/{membershipId}").
To resolve a membership from a member email or external id, use
lookup-membership first.
opts:
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(get-membership-graph client parent & [opts])Get a graph showing all transitive paths from a member to a group, or among the members of a group. Returns an Operation; the resulting MembershipGraph carries adjacency lists describing the traversal.
parent is the group's resource name ("groups/{groupId}") or the
synthetic "groups/-" for member-centric traversal. The SDK appends
"/memberships:getMembershipGraph" to form the URL.
opts:
Get a graph showing all transitive paths from a member to a group, or
among the members of a group. Returns an Operation; the resulting
MembershipGraph carries adjacency lists describing the traversal.
`parent` is the group's resource name ("groups/{groupId}") or the
synthetic "groups/-" for member-centric traversal. The SDK appends
"/memberships:getMembershipGraph" to form the URL.
opts:
- :query — REQUIRED; CEL expression naming the member of interest
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(list-groups client parent & [opts])List groups under the given parent (a customer resource name, e.g. "customers/C012345"). Pagination via :page-token; the response key is :groups.
opts:
List groups under the given parent (a customer resource name, e.g.
"customers/C012345"). Pagination via :page-token; the response key
is :groups.
opts:
- :view — :basic (default; returns name, group-key, parent only)
or :full (includes labels, description, etc.)
- :page-size, :page-token
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(list-memberships client parent & [opts])List memberships of a group. parent is the group's resource name
("groups/{groupId}"). Response key is :memberships.
opts:
List memberships of a group. `parent` is the group's resource name
("groups/{groupId}"). Response key is :memberships.
opts:
- :view — :basic (default) or :full
- :page-size, :page-token, :fields
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(lookup-group client & [opts])Look up a group's resource name by its group-key id (email or external id). Returns {:data {:name "groups/{groupId}"}}.
opts:
Look up a group's resource name by its group-key id (email or external
id). Returns {:data {:name "groups/{groupId}"}}.
opts:
- :group-key-id — REQUIRED; the email address or external id
- :group-key-namespace — required for external-id lookup (omit for
email-based lookup); namespace identifying
the external system
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(lookup-membership client parent & [opts])Look up a membership's resource name within a group by member-key id. Returns {:data {:name "groups/{groupId}/memberships/{membershipId}"}}.
parent is the group's resource name ("groups/{groupId}").
opts:
Look up a membership's resource name within a group by member-key id.
Returns {:data {:name "groups/{groupId}/memberships/{membershipId}"}}.
`parent` is the group's resource name ("groups/{groupId}").
opts:
- :member-key-id — REQUIRED; the member's email or external id
- :member-key-namespace — required for external-id lookup
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(modify-membership-roles client membership-name request & [opts])Modify a membership's roles. Add, remove, or update existing roles on a single membership. Non-LRO — returns the updated Membership synchronously.
membership-name is the resource name
("groups/{groupId}/memberships/{membershipId}").
request is a Clojure map with kebab-case keys:
:add-roles — vector of role maps to add
(e.g. [{:name "OWNER"}])
:remove-roles — vector of role NAME strings to remove
(e.g. ["MEMBER"])
:update-roles-params — vector of update-params maps for changes
that are neither pure-add nor pure-remove
(e.g. role expiry adjustments). Each entry:
{:field-mask "expiryDetail.expireTime"
:membership-role {:name "MEMBER"
:expiry-detail {:expire-time "..."}}}
opts:
Modify a membership's roles. Add, remove, or update existing roles
on a single membership. Non-LRO — returns the updated Membership
synchronously.
`membership-name` is the resource name
("groups/{groupId}/memberships/{membershipId}").
`request` is a Clojure map with kebab-case keys:
:add-roles — vector of role maps to add
(e.g. [{:name "OWNER"}])
:remove-roles — vector of role NAME strings to remove
(e.g. ["MEMBER"])
:update-roles-params — vector of update-params maps for changes
that are neither pure-add nor pure-remove
(e.g. role expiry adjustments). Each entry:
{:field-mask "expiryDetail.expireTime"
:membership-role {:name "MEMBER"
:expiry-detail {:expire-time "..."}}}
opts:
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(search-direct-groups client parent & [opts])Search the groups a given member belongs to DIRECTLY (not transitively). The direct counterpart to search-transitive-groups. Response key is :memberships (each entry a GroupRelation).
parent is the synthetic placeholder "groups/-". The SDK appends
"/memberships:searchDirectGroups" to form the URL.
opts:
Search the groups a given member belongs to DIRECTLY (not transitively). The direct counterpart to search-transitive-groups. Response key is :memberships (each entry a GroupRelation). `parent` is the synthetic placeholder "groups/-". The SDK appends "/memberships:searchDirectGroups" to form the URL. opts: - :query — REQUIRED; CEL expression naming the member - :order-by — e.g. "groupKey" or "displayName" - :page-size, :page-token, :fields - :read-timeout-ms — per-request read timeout override - :connect-timeout-ms — per-request connect timeout override
(search-groups client & [opts])Search groups by a CEL-style query. Common query forms: "parent == 'customers/C012345'" "parent == 'customers/C012345' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels"
Response key is :groups.
opts:
Search groups by a CEL-style query. Common query forms: "parent == 'customers/C012345'" "parent == 'customers/C012345' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels" Response key is :groups. opts: - :query — REQUIRED in any meaningful call; CEL filter expression - :view — :basic (default) or :full - :page-size, :page-token, :fields - :read-timeout-ms — per-request read timeout override - :connect-timeout-ms — per-request connect timeout override
(search-transitive-groups client parent & [opts])Search the groups a given member belongs to, transitively. Returns {:data [GroupRelation ...]} via response key :memberships (the API wraps each ancestor as a GroupRelation).
parent is the synthetic placeholder "groups/-" (a hyphen for the
group id) — Cloud Identity treats this as the member-centric
traversal entry point. The SDK appends
"/memberships:searchTransitiveGroups" to form the URL. Despite the
method name, the query identifies the MEMBER, not a group.
opts:
Search the groups a given member belongs to, transitively. Returns
{:data [GroupRelation ...]} via response key :memberships (the API
wraps each ancestor as a GroupRelation).
`parent` is the synthetic placeholder "groups/-" (a hyphen for the
group id) — Cloud Identity treats this as the member-centric
traversal entry point. The SDK appends
"/memberships:searchTransitiveGroups" to form the URL. Despite the
method name, the query identifies the MEMBER, not a group.
opts:
- :query — REQUIRED; CEL expression naming the member, e.g.
"member_key_id == 'alice@example.com' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels"
- :page-size, :page-token, :fields
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(search-transitive-memberships client parent & [opts])Search the memberships of a group transitively (members of the group plus members of nested groups). Response key is :memberships.
parent is the group's resource name ("groups/{groupId}"). The SDK
appends "/memberships:searchTransitiveMemberships" to form the URL.
Note this endpoint takes NO :query opt — it always returns all
transitive memberships of the parent group.
opts:
Search the memberships of a group transitively (members of the group
plus members of nested groups). Response key is :memberships.
`parent` is the group's resource name ("groups/{groupId}"). The SDK
appends "/memberships:searchTransitiveMemberships" to form the URL.
Note this endpoint takes NO :query opt — it always returns all
transitive memberships of the parent group.
opts:
- :page-size, :page-token, :fields
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout override(update-group client group-name group & [opts])Partially update a group (PATCH; LRO). Cloud Identity v1 exposes PATCH but NOT PUT — there is no replace-group. Returns an Operation; see create-group for polling semantics.
group-name is the resource name ("groups/{groupId}").
group is a Clojure map of fields to update. Only fields listed in
:update-mask are applied; absent paths in the mask are left
unchanged.
opts:
Partially update a group (PATCH; LRO). Cloud Identity v1 exposes
PATCH but NOT PUT — there is no replace-group. Returns an Operation;
see create-group for polling semantics.
`group-name` is the resource name ("groups/{groupId}").
`group` is a Clojure map of fields to update. Only fields listed in
`:update-mask` are applied; absent paths in the mask are left
unchanged.
opts:
- :update-mask — comma-separated field paths to apply
(e.g. "displayName,description"). REQUIRED for any
non-trivial update; without it the API returns an error.
- :fields — partial response field mask string
- :read-timeout-ms — per-request read timeout override
- :connect-timeout-ms — per-request connect timeout overridecljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |