Enable Google sign-in
Google sign-in can run alone or alongside generic OIDC. Email and password stay the default. An Installation administrator attaches a person's Google identity to an existing OpenClaw Enterprise (OCE) account; that person can then sign in with Google or with the account password. Google sign-in creates no account, performs no signup, and never matches accounts by email address.
Google uses the same guarded
single-controller profile
as OIDC: the exact Origin checks, PKCE (S256), one-use state, the host-only
__Host- browser-binding cookie, the keyed admission limiter, the eight-hour session
rules, and the attemptId, login receipt, and one-use result exchange. Password
fallback, account disablement, detach, and the recovery account work unchanged. You can
enable Google alone or together with OIDC.
Requirements
- Everything the external sign-in profile
requires: one serving controller, PostgreSQL State, native IAM, one canonical HTTPS
Console origin, and
agentNativeAdmin.enabled: false. - A controller image that includes Google sign-in: a published image from a commit that includes it, or your own build.
- A Google Cloud project where you can create an OAuth client.
- API Pod HTTPS egress to
oauth2.googleapis.com(code exchange) andwww.googleapis.com(signing keys). Browsers, not the API, reachaccounts.google.com.
Create the Google OAuth client
- In the Google Cloud console, configure the OAuth consent screen. For a Google
Workspace organization, choose Internal so only your organization's accounts can
consent. The controller requests only the
openidandemailscopes. - Under APIs & Services > Credentials, create an OAuth client ID of type Web application.
- Add exactly one authorized redirect URI:
OCC_AUTH_BASE_URLfollowed by/api/auth/providers/google/callback, for examplehttps://occ.example.com/api/auth/providers/google/callback. The controller builds this URI fromOCC_AUTH_BASE_URL; any difference makes Google reject the request. No JavaScript origin is needed. - Save the client ID and client secret to protected files.
The controller uses Google's documented OpenID Connect endpoints as fixed values. It does not fetch the discovery document at runtime.
Configure the chart
Create a dedicated Secret. It must differ from every other Secret the chart reads,
including auth.oidc.secretName:
kubectl -n openclaw-system create secret generic occ-google-login \ --from-file=client-id=/secure/occ/google-client-id \ --from-file=client-secret=/secure/occ/google-client-secretThen set these protected values:
auth: recoveryUserId: "<recovery administrator user ID>" google: enabled: true secretName: occ-google-login clientIdKey: client-id clientSecretKey: client-secret allowedDomains: [] # optional, for example ["example.com"] egressCidrs: [] # optional IPv4 CIDRsagentNativeAdmin: enabled: falseauth.recoveryUserId is required whenever OIDC or Google is enabled, including a
Google-only install. It names an existing local password administrator; read it as that
administrator from data.user.id of GET /api/auth/session. The chart passes it as
OCC_AUTH_RECOVERY_USER_ID, which designates the recovery account for either
provider. Rendering fails on incomplete Google values, a shared Secret, an HTTP base URL,
native administration, an invalid CIDR, or an allowed domain that is not a DNS name. It
also fails when allowedDomains is set without auth.google.enabled.
The chart adds the API-only NetworkPolicy
openclaw-enterprise-api-google-login-egress on TCP 443. Empty
auth.google.egressCidrs allows any address except link-local 169.254.0.0/16. Google
publishes no small, stable address range for these hosts, so narrow egress with an egress
proxy rather than static CIDRs.
The API reads these variables; see production settings:
| Variable | Source |
|---|---|
OCC_AUTH_GOOGLE_CLIENT_ID |
auth.google Secret key clientIdKey |
OCC_AUTH_GOOGLE_CLIENT_SECRET |
auth.google Secret key clientSecretKey |
OCC_AUTH_GOOGLE_ALLOWED_DOMAINS |
auth.google.allowedDomains, comma-joined when non-empty |
OCC_AUTH_RECOVERY_USER_ID |
auth.recoveryUserId |
Restrict hosted domains
With allowedDomains empty, any Google account whose identity an administrator attached
can sign in. With one or more domains set, the ID token must also carry a hosted-domain
(hd) claim equal to one of them and email_verified: true. Personal Google accounts
carry no hd claim and are refused. The controller compares domains in lowercase. The
email address itself is never used for identity or authorization.
Enable it
Enable Google during the same stopped maintenance as the
external sign-in procedure: verify
password recovery, create the Secret, set the values above, close ingress, stop
identity writers, run helm upgrade, and verify through
restricted access before
reopening ingress. If the guarded profile is already active through OIDC, adding
Google needs no new activation, but still use one serving controller and stopped
writers for the upgrade.
GET /api/auth/providers then returns google: true, and the Console shows
Continue with Google. Once every ordinary account has an identity,
recovery-only password sign-in
leaves passwords to the recovery account. Activation is one-way: keep at least one provider configured,
or startup refuses. To return to password-only sign-in, follow
sign-in maintenance, then set
auth.google.enabled: false as well; without Helm also remove the
OCC_AUTH_GOOGLE_* variables.
Find a person's Google subject
OCE identifies a Google account only by the ID token's sub claim, a stable account
identifier. Email addresses can change owners and are never identity keys.
- Google Workspace: the user's
idfrom the Admin SDK Directory API equals the OpenID Connectsub. An administrator can read it withGET https://admin.googleapis.com/admin/directory/v1/users/<email>and theidfield of the response. - Consumer Google accounts: there is no administrator lookup. The person must supply
their
sub, for example from an ID token they obtain themselves. Verify that the person controls that account through your own identity process.
Attach and detach
As a human Installation administrator, sign in as a human administrator
so OCC_URL, OCC_ORIGIN and OCC_SESSION_COOKIE_JAR are set, and set USER_ID to the
account's id. Read the account's current version, then attach the subject:
VERSION="$(curl --fail-with-body --silent --show-error \ --cookie "$OCC_SESSION_COOKIE_JAR" -H "Origin: $OCC_ORIGIN" \ "$OCC_URL/api/auth/accounts/$USER_ID" | jq -er .data.version)" &&jq -n --arg subject '<google sub>' --argjson version "$VERSION" \ '{subject: $subject, expectedVersion: $version}' | curl --fail-with-body --silent --show-error \ --cookie "$OCC_SESSION_COOKIE_JAR" -H "Origin: $OCC_ORIGIN" \ -H 'Content-Type: application/json' --data-binary @- \ "$OCC_URL/api/auth/accounts/$USER_ID/providers/google"The subject is 1–255 printable ASCII characters without spaces. The call returns 409
when Google is not configured, the version is stale, the account is disabled, or another
account holds the subject ("The external identity is already assigned."). Attachment
advances the account version and ends the account's existing sessions. The account read then lists a method whose providerId starts with
google:. Detach it with
POST /api/auth/accounts/:userId/methods/:methodId/detach, as for OIDC. Detaching ends
every session of the account, password sessions included; the password keeps working for
new sign-ins.
Rotation and outages
The provider instance is derived from the client ID. A new client ID is a new provider
instance: reattach every Google identity, then detach the old methods by methodId.
Sessions signed in under the old client ID, or with Google once it is removed, end on
their next request.
Rotating only the client secret keeps attachments and invalidates pending sign-in
attempts. Rotating OCC_AUTH_SECRET also fails attempts in flight.
A Google outage, blocked egress, or rejected ID token fails that sign-in closed and
returns the browser to /console/?authError=google; password sign-in is unaffected. An
outage adds authReason=provider-unavailable, and the Console says Google sign-in is
unavailable right now.
Google start and callback share the OIDC admission budget, so enabling both does not
raise the external sign-in limits.
