Google Workspace Account Request Workflow¶
A step-by-step guide to creating a self-service workflow that lets users request a Google Workspace account through the request catalog, routes it for approval, and automatically provisions the account and links it to the requestor's Floh identity.
This guide is also a useful end-to-end example workflow that exercises most of Floh's workflow-authoring features: request catalog publication, submitter interpolation, connector steps with design-time validation, transform-step sandboxing, approval routing, identity linking, and notifications.
Prerequisites¶
- A Google Workspace connector configured and passing the test connection — see Configuring a Google Workspace Connector.
- A group named
google-account-approvers(or similar) with at least one member. Create it under Groups in the admin sidebar. - The
workflow:managepermission on your admin account. - At least one organizational unit (OU) in Google Admin Console you want new accounts to land in — note its full path (for example,
/TEST). If you're unsure, leave the default/for now; the designer typeahead (Step 3.4) will list the valid options.
Overview¶
Portal Submit
│
▼
Start
│
▼
Derive Account Details (transform)
│
▼
Approval Gate (group: google-account-approvers)
│
├── approved ──► Create Google Account (connector)
│ │
│ ▼
│ Link Google Identity (identity_link)
│ │
│ ▼
│ Notify — Account Created (notification)
│ │
│ ▼
│ End
│
└── rejected ──► Notify — Rejected (notification) ──► End
Step 1 — Create the workflow¶
- Navigate to Workflows and click New Workflow.
- Fill in:
| Field | Value |
|---|---|
| Name | Google Workspace Account Request |
| Description | Self-service request for a new Google Workspace account |
| Category | User Self-Service |
| Subject Variable | targetUser (auto-populated by the category) |
| Error Strategy | stop |
| Trigger | manual |
The User Self-Service category is the preferred way to author portal-submitted
workflows that target the requesting user: the designer automatically creates a
targetUser variable (a user-type variable flagged as self-service) and wires
it as the subject variable. You don't need to add it manually. The category
also handles admin submit-on-behalf-of flows — onBehalfOfUserId rebinds
targetUser while {{submitter.*}} continues to reflect the real caller, so
there is no need to switch categories for that case. The plain User
category is only for workflows whose subject is not the self-service
targetUser (e.g. an approval workflow targeting a user different from the
submitter where the submitter picks the target explicitly). See
docs/workflows/user-self-service.md for details.
- Assign the workflow to your project.
Step 2 — Define variables¶
Open the Variables tab. The User Self-Service category has already
seeded a locked targetUser row for you; add the rest:
| Name | Type | Required | Default Value | Description |
|---|---|---|---|---|
targetUser |
Target User | yes | — (auto-provided) | The requesting user (auto-filled from session) |
firstName |
String |
yes | {{submitter.firstName}} |
First name for the Google account |
lastName |
String |
yes | {{submitter.lastName}} |
Last name for the Google account |
justification |
String |
no | — | Business justification (shown to approvers) |
Notes:
- The Target User row is auto-provided because you picked the User Self-Service category. The designer locks it (you can't rename or re-type it) so the engine's implicit synthesis doesn't fall out of sync. Under the hood it's a
user-typed variable withselfService: true. In scripts and templates you can reference its attributes via{{targetUser.id}},{{targetUser.email}},{{targetUser.displayName}}, etc. - On catalog submit the portal form hides self-service variables and the server binds them to the authenticated submitter (or to the on-behalf-of target for admins holding the
workflow:submit_on_behalf_ofpermission — see the user-self-service doc for details). Any caller-supplied value is ignored. - On
Stringvariables the Default Value field accepts literal text, a{{submitter.*}}expression, or a mix of the two. Supported attributes:{{submitter.firstName}},{{submitter.lastName}},{{submitter.email}},{{submitter.displayName}},{{submitter.id}}.{{submitter.*}}always reflects the real authenticated caller — even when an admin submits on behalf of another user — so audit trails and notification bodies can't be spoofed via the on-behalf-of override. - The same pre-fill applies in the admin Test Run dialog (Step 6), so you can test the workflow exactly the way a requestor will experience it.
Step 3 — Add the workflow steps¶
3.1 — Start¶
Type: start. Entry point.
3.2 — Derive Account Details¶
Type: transform.
| Config Field | Value |
|---|---|
| Script | See below |
| Outputs | primaryEmail, initialPassword |
Script:
const targetUser = floh.variables.targetUser;
const firstName = floh.variables.firstName;
const lastName = floh.variables.lastName;
// Derive the primary email from the target user's existing email local-part so
// there's no collision with an existing Google user. Replace the domain with
// your Google Workspace primary domain.
const localPart = targetUser.email.split("@")[0];
const primaryEmail = `${localPart}@your-workspace-domain.com`;
// Generate a 24-character initial password. Google rejects passwords shorter
// than 8 chars; we include at least one char from each class for safety.
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%";
let initialPassword = "";
for (let i = 0; i < 24; i++) {
initialPassword += charset.charAt(Math.floor(Math.random() * charset.length));
}
return { primaryEmail, initialPassword };
Replace your-workspace-domain.com with your actual primary Google Workspace domain.
Tip — test the script before saving: expand the Test Script panel under the transform step. The Mock Variables (JSON) textarea is prepopulated from your workflow variables (including the targetUser object, the submitter snapshot, and resolved {{submitter.*}} defaults), so you can run the script against realistic inputs and inspect the primaryEmail/initialPassword output without leaving the designer. Click Load sample to regenerate the mock if you change variable definitions.
3.3 — Approval Gate¶
Type: approval.
| Config Field | Value |
|---|---|
| Approvers | group:google-account-approvers |
The designer shows a hint under the field resolving the group UUID to its friendly name (e.g., Resolves to: group:google-account-approvers) so you don't need to memorize UUIDs.
Transitions:
success→ Create Google Accounterror→ Notify — Rejected
3.4 — Create Google Account¶
Type: connector.
| Config Field | Value |
|---|---|
| Connector | your Google Workspace connector instance |
| Command | createUser |
| primaryEmail | {{primaryEmail}} |
| firstName | {{firstName}} |
| lastName | {{lastName}} |
| password | {{initialPassword}} |
| orgUnitPath | a literal path (e.g. /TEST) — see below |
| Output Key | provisionAccount |
The orgUnitPath field has a typeahead dropdown backed by the connector's listOrgUnits command. Click into the field to see the live list of organizational units from your Google Admin domain; pick one to avoid INVALID_OU_ID at runtime. If you type a literal path, the designer validates it on Save using getOrgUnit and surfaces an explicit error like Create Google Account — orgUnitPath: The organizational unit "/DoesNotExist" was not found. Invalid values block publish; the check is skipped for {{…}} expressions (those are validated at runtime).
Google automatically sets changePasswordAtNextLogin: true, so the provisioned user must change their password on first sign-in.
The step produces three output variables (promoted flat into the workflow namespace): created, userId, primaryEmail. Because we set Output Key to provisionAccount, the raw API result is also available under {{provisionAccount}} if you need it.
3.5 — Link Google Identity¶
Type: identity_link.
| Config Field | Value |
|---|---|
| User ID | {{targetUser.id}} |
| Connector | your Google Workspace connector instance |
| External ID | {{userId}} |
| External Email | {{primaryEmail}} |
| External Display Name | {{firstName}} {{lastName}} |
identity_link writes a row to the user_external_identity table, formally linking the Floh user ({{targetUser.id}}) to their account in the connector-managed external system. Once linked, the connector's sync passes will recognize the same account and keep downstream profile attributes (department, orgUnitPath, etc.) in sync.
Common pitfall:
User IDmust be the Floh user UUID ({{targetUser.id}}), andExternal IDmust be the Google user ID from the previous step ({{userId}}). Swapping them produces a foreign-key violation. The designer's autocomplete lists both correctly from the resolved step outputs.
3.6 — Notify — Account Created¶
Type: notification.
| Config Field | Value |
|---|---|
| Recipient Type | internal |
| Recipient User | {{targetUser.id}} |
| Subject Override | Your Google Workspace account has been created |
| Custom Body | Your Google Workspace account has been provisioned at {{primaryEmail}}. You will be prompted to set your password on first sign-in. Justification: {{justification}} |
3.7 — Notify — Rejected¶
Type: notification.
| Config Field | Value |
|---|---|
| Recipient Type | internal |
| Recipient User | {{targetUser.id}} |
| Subject Override | Google Workspace account request not approved |
| Custom Body | Your request for a Google Workspace account was not approved. Contact your manager or IT for more information. |
3.8 — End¶
Type: end. Exit point.
Step 4 — Wire the graph¶
In the Graph tab, draw these transitions:
- Start → Derive Account Details
- Derive Account Details → Approval Gate
- Approval Gate →
success→ Create Google Account - Approval Gate →
error→ Notify — Rejected - Create Google Account → Link Google Identity
- Link Google Identity → Notify — Account Created
- Notify — Account Created → End
- Notify — Rejected → End
Step 5 — Save and validate¶
Click Save. The designer runs two validation passes:
- Static validation — unreachable steps, duplicate output keys, missing required fields on every step type (including
identity_link's requiredUser ID,Connector, andExternal ID). - Connector field validation — any literal step-config value that references a connector-managed resource (like
orgUnitPath) is validated against the connector in-place. Errors appear in the banner as<step> — <param>: <error>and block publish until resolved.
Fix any errors and save again.
Step 6 — Test Run before publishing¶
You can exercise the workflow end-to-end from the admin UI without publishing it:
- On the workflow detail page, click Test Run.
- A dialog lists the workflow's input variables. The
targetUservariable is hidden (it's auto-filled from your session), andfirstName/lastNameare pre-filled from the{{submitter.*}}defaults. Fill injustificationif required. - Click Start Run.
- Watch the run progress in the Runs tab. Approve the pending task from your task inbox, then confirm the Google account was created (check Google Admin Console) and that the new link shows up under Users → {targetUser.displayName} → External Identities (also exposed at
GET /users/{targetUser.id}/external-identities).
If any step fails, expand its variables in the run viewer and inspect the error. Common fixes:
| Symptom | Fix |
|---|---|
Create Google Account fails with INVALID_OU_ID |
The literal orgUnitPath doesn't exist. Use the typeahead or run the listOrgUnits command on the connector's Commands tab to see valid paths. |
Save fails with orgUnitPath: Google API error (403): insufficientPermissions |
The connector's Domain-wide Delegation entry is missing the admin.directory.orgunit.readonly scope. Add it in Google Admin Console → Security → API controls → Manage Domain-wide Delegation, save, and retry. See Google Workspace setup → Grant Domain-Wide Delegation. |
Create Google Account fails with Entity already exists |
A Google user with that primary email already exists. Google retains deleted accounts for several days — pick a different local-part or wait. |
Link Google Identity fails with a foreign-key violation |
User ID is the Google numeric ID instead of the Floh UUID. Change it to {{targetUser.id}}. |
Link Google Identity fails with "Connector not found" |
The Connector value is a name that doesn't match. Pick the connector from the dropdown or paste its UUID. |
| Approval never transitions | The approvers group is empty. Confirm google-account-approvers has at least one member, or let the configured approval-fallback rule route to the system admin group. |
Step 7 — Publish and add to the catalog¶
- Click Publish to activate the workflow.
- Open the Catalog tab on the workflow detail page.
- Configure:
| Field | Value |
|---|---|
| Published | checked |
| Icon | person_add |
| Description | Request a new Google Workspace account. Requires approval from IT. |
| Tags | google, account, provisioning |
| Submission Groups | leave empty (all authenticated users), or restrict to specific groups |
Changes auto-save after a short debounce — no separate Save click is required on this tab.
What users see¶
When a user opens the Request Catalog in the portal:
- They see the "Google Workspace Account Request" card.
- They click Submit Request.
- A form appears with:
- firstName (pre-filled from
{{submitter.firstName}}) - lastName (pre-filled from
{{submitter.lastName}}) - justification (optional)
- The
targetUserfield is invisible — it is auto-populated with their user ID on submission. - After submission, the request appears in the
google-account-approversgroup's task inbox. - Once approved, the target user receives the "account created" notification with their new
primaryEmailand sign-in instructions.
Identity linking (how it works)¶
The identity_link step writes a row to the user_external_identity table with the Floh user ID, connector ID, and the Google user ID as external_id. This is the canonical way to link a Floh user to an account in a connector-managed external system; it supersedes the older pattern of stashing the Google ID as a profile custom attribute.
Two complementary linking paths keep the graph accurate:
- OIDC sign-in — when the user first signs in via Google (
https://accounts.google.comas the OIDC issuer), Floh's auth callback setsupstream_issuerandupstream_idfrom the ID token claims on the user record itself. - Connector sync — if user sync is configured on the Google Workspace connector with the Email or Email + Issuer match strategy, each sync pass re-confirms (or creates) the
user_external_identityrow. Provisioning workflows that useidentity_linkare already compatible with this path.
What's next¶
- Command reference — full list of commands, parameters, and output variables
- Connector sync — keep Floh in sync with the Google directory
- External identities — inspect and manage per-user connector identity links
- Password reset workflow — self-service password reset using the
setPasswordconnector command - Creating workflows — build more workflows following the same patterns