Collect Workday HCM logs
This document explains how to ingest Workday HCM logs to Google Security Operations by setting up a feed using the Third Party API.
The parser extracts Workday HCM user data from JSON-formatted logs. It handles various data transformations, including renaming fields, merging nested objects, parsing dates, and populating UDM fields for user attributes, employment details, and organizational structure.
Before you begin
Ensure that you have the following prerequisites:
- A Google SecOps instance
- Privileged access to Workday with Security Administratoror equivalent permissions
Configure Workday API authentication
Create an Integration System User (ISU)
- Sign in to Workday with administrative privileges.
- In the search bar, type Create Integration System Userand select the task.
- Enter a Username(for example,
ISU_SecOps_HCM). - Set a Password.
- Set Session Timeout Minutesto
0to prevent the ISU from timing out. - Enable Do Not Allow UI Sessionsto enhance security by restricting UI logins.
- Go to the Maintain Password Rulestask.
- Add the integration system user to the System Users exempt from password expirationfield.
Create an integration security group
- In the search bar, type Create Security Groupand select the task.
- Locate the Type of Tenanted Security Groupfield, and select Integration System Security Group (Unconstrained).
- Provide a Namefor the security group (for example,
ISG_SecOps_HCM). - Click OK.
- Click Editfor the newly created security group.
- Assign the Integration System User from the previous step to the security group.
- Click Done.
Grant domain access to the security group
The Google SecOps feed retrieves data from four Workday REST API endpoints. Each endpoint requires specific Domain Security Policy permissions to be granted to the integration security group.
- In the search bar, type Maintain Permissions for Security Groupand select the task.
- Choose the security group you created (for example,
ISG_SecOps_HCM) from the Source Security Grouplist. - Click OK.
- Go to Domain Security Policy Permissions.
-
Add GETaccess for each of the following domains:
API Endpoint Required Domain Security Policies /workers— Worker list and profilesWorker Data: Public Worker Reports/workers/{id}/timeOffEntries— Time off balancesWorker Data: Time Off (Time Off Balances),Worker Data: Time Off (Time Off Balances Manager View)/workers/{id}/history— Worker staffing historyWorker Data: Historical Staffing Information/supervisoryOrganizations— Org structureManage: Supervisory OrganizationorView: Supervisory Organization -
Click OK.
-
Click Doneto save changes.
Activate security policy changes
- In the search bar, type Activate Pending Security Policy Changesand select the task.
- Enter a reason for the change in the comment field (for example,
Granting API access for Google SecOps HCM integration). - Click OK.
- Select Confirm, then click OK.
Register API client for integrations
- In the search bar, type Register API Client for Integrationsand select it.
- Click Create.
-
Provide the following configuration details:
- Client Name: Enter a name (for example,
Google SecOps HCM Client). - System User: Select the Integration System User you created (for example,
ISU_SecOps_HCM). -
Scope: Select the following scopes:
Scope Required for Staffing /workersand/workers/{id}/historyendpointsTime Off and Leave /workers/{id}/timeOffEntriesendpointOrganizations and Roles /supervisoryOrganizationsendpoint
- Client Name: Enter a name (for example,
-
Click Save.
-
Click OK.
-
Copy and save the Client IDand Client Secretimmediately.
Generate OAuth 2.0 refresh token
- In the search bar, type Manage Refresh Tokens for Integrationsand select it.
- Click Generate New Refresh Token.
- In the Workday Accountfield, search for and select the Integration System User (for example,
ISU_SecOps_HCM). - Select the API client you created and click OK.
- Copy and save the Refresh Token.
Get API endpoint URLs
- In the search bar, type View API Clientsand select it.
- Under API Clients for Integrations, locate the client you created (for example,
Google SecOps HCM Client). -
Copy and save the following details:
- Token Endpoint: The URL to obtain an access token (for example,
https://wd2-impl-services1.workday.com/ccx/oauth2/YOUR_TENANT/token). - Workday REST API Endpoint: The base URL for API calls (for example,
https://wd2-impl-services1.workday.com/ccx/api/v1/YOUR_TENANT).
- Token Endpoint: The URL to obtain an access token (for example,
Generate OAuth access token
-
Use
curlor a similar HTTP client to send a POST request to the Token Endpoint:curl -X POST "https://HOSTNAME/ccx/oauth2/TENANT/token" \ -d "grant_type=refresh_token" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "refresh_token=YOUR_REFRESH_TOKEN"
This returns an access token (for example, "access_token": "abcd1234"
). Copy and save the access token.
Verify API access
-
Before configuring the feed, verify that the ISU has the required permissions for the key endpoints. Replace the variables with your actual values:
TOKEN = "your-access-token" HOST = "your-workday-host" TENANT = "your-tenant" # Test 1: Workers (should return worker list) curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer $TOKEN " \ "https:// $HOST /ccx/api/v1/ $TENANT /workers?limit=1" # Test 2: Time off entries (replace WORKER_ID with an ID from Test 1) curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer $TOKEN " \ "https:// $HOST /ccx/api/v1/ $TENANT /workers/WORKER_ID/timeOffEntries" # Test 3: Worker history (replace WORKER_ID with an ID from Test 1) curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer $TOKEN " \ "https:// $HOST /ccx/api/v1/ $TENANT /workers/WORKER_ID/history" # Test 4: Supervisory organizations curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer $TOKEN " \ "https:// $HOST /ccx/api/v1/ $TENANT /supervisoryOrganizations"
Each test should return HTTP status 200
. If any endpoint returns 403
, see the Troubleshooting
section.
Configure a feed in Google SecOps to ingest Workday HCM data
Set up the feed
- Go to SIEM Settings > Feeds.
- Click Add New Feed.
- On the next page, click Configure a single feed.
- In the Feed namefield, enter a name for the feed (for example,
Workday HCM). - Select Third Party APIas the Source type.
- Select Workdayas the Log type.
- Click Next.
Configure feed parameters
-
Specify values for the following input parameters:
-
API Hostname: The fully qualified domain name of your Workday REST API endpoint (for example,
wd2-impl-services1.workday.com). -
Tenant: The last path element of your Workday REST API endpoint that identifies your Workday instance.
-
Access token: The OAuth access token generated in the previous section.
Advanced Options:
- Asset namespace: The asset namespace .
- Ingestion labels: The label to be applied to the events from this feed.
-
-
Click Next.
-
Review your new feed configuration in the Finalizescreen, and then click Submit.
Troubleshooting
403 Forbidden on specific endpoints
If the feed reports errors or the verification curl commands return 403
for specific endpoints, the Integration System User is missing permissions.
| Failing endpoint | Fix |
|---|---|
/workers/{id}/timeOffEntries
|
Add GETaccess for Worker Data: Time Off (Time Off Balances)
and Worker Data: Time Off (Time Off Balances Manager View)
domains. Add Time Off and Leavescope to the API client. |
/workers/{id}/history
|
Add GETaccess for Worker Data: Historical Staffing Information
domain. Verify the Staffingscope is assigned to the API client. |
/supervisoryOrganizations
|
Add GETaccess for Manage: Supervisory Organization
or View: Supervisory Organization
domain. Add Organizations and Rolesscope to the API client. |
After making permission changes:
- Run Activate Pending Security Policy Changesin Workday.
- If you added new scopes to the API client, generate a new refresh token via Manage Refresh Tokens for Integrationsand then generate a new access token.
- Update the feed configuration with the new access token if changed.
Authentication errors
- 401 Unauthorized: The access token has expired. Generate a new token using the refresh token and update the feed.
- Invalid client: Verify the Client ID and Client Secret are correct.
- Invalid refresh token: The refresh token may have been revoked. Generate a new one via Manage Refresh Tokens for Integrations.
UDM mapping table
| Log Field | UDM Mapping | Logic |
|---|---|---|
@timestamp
|
metadata.event_timestamp.seconds
|
Parsed as a timestamp in seconds since epoch |
businessTitle
|
entity.entity.user.title
|
Directly mapped |
descriptor
|
entity.entity.user.user_display_name
|
Directly mapped |
Employee_ID
|
entity.entity.user.employee_id
|
Directly mapped |
Employee_ID
|
entity.metadata.product_entity_id
|
Mapped when id
is not present |
gopher-supervisor.descriptor
|
entity.entity.user.managers.user_display_name
|
Directly mapped |
gopher-supervisor.id
|
entity.entity.user.managers.product_object_id
|
Directly mapped |
gopher-supervisor.primaryWorkEmail
|
entity.entity.user.managers.email_addresses
|
Directly mapped |
gopher-time-off.date
|
entity.entity.user.time_off.interval.start_time
|
Parsed as a date |
gopher-time-off.descriptor
|
entity.entity.user.time_off.description
|
Directly mapped |
Hire_Date
|
entity.entity.user.hire_date
|
Parsed as a date |
id
|
entity.metadata.product_entity_id
|
Directly mapped when present |
Job_Profile
|
entity.entity.user.title
|
Mapped when businessTitle
is not present |
Legal_Name_First_Name
|
entity.entity.user.first_name
|
Directly mapped |
Legal_Name_Last_Name
|
entity.entity.user.last_name
|
Directly mapped |
location.descriptor
|
entity.entity.location.city
|
Directly mapped |
primarySupervisoryOrganization.descriptor
|
entity.entity.user.department
|
Directly mapped |
primaryWorkEmail
|
entity.entity.user.email_addresses
|
Directly mapped |
primaryWorkPhone
|
entity.entity.user.phone_numbers
|
Directly mapped |
Termination_Date
|
entity.entity.user.termination_date
|
Parsed as a date |
Work_Email
|
entity.entity.user.email_addresses
|
Mapped when primaryWorkEmail
is not present |
collection_time
|
metadata.event_timestamp.collected_timestamp
|
Directly mapped |
Change Log
View the Change Log for this parser
Need more help? Get answers from Community members and Google SecOps professionals.

