Hello,
I am looking to add a particular value to an existing search of Okta data. The problem is I don't know how to extract the value which is on the same level as other values. The value I am looking for is "Workflows Administrator". The existing search is:
index=okta "debugContext.debugData.privilegeGranted"="*" | rename actor.displayName as "Actor", targetUserDisplayName as "Target Name", targetUserAlternateId as "Target ID", description as "Action", debugContext.debugData.privilegeGranted as "Role(s)" | eval Time = strftime(_time, "%Y-%d-%m %H:%M:%S") | fields - _time | table Time, Actor, Action, "Target Name", "Target ID", Action, "Role(s)"
and sample data is
{ [-]
actor: { [+]
}
authenticationContext: { [+]
}
client: { [+]
}
debugContext: { [-]
debugData: { [-]
privilegeGranted: Application administrator (all), User administrator (all), Help Desk administrator (all)
}
}
device: null
displayMessage: Grant user privilege
eventType: user.account.privilege.grant
legacyEventType: core.user.admin_privilege.granted
outcome: { [-]
reason: null
result: SUCCESS
}
published: 2025-05-08T19:30:54.612Z
request: { [-]
ipChain: [ [+]
]
}
securityContext: { [-]
asNumber: null
asOrg: null
domain: null
isProxy: null
isp: null
}
severity: INFO
target: [ [-]
{ [-]
alternateId: jdoe@company.com
detailEntry: null
displayName: John Doe
id: 00umfyv9jwzVvafI71t7
type: User
}
{ [-]
alternateId: unknown
detailEntry: null
displayName: Custom role binding added
id: CUSTOM_ROLE_BINDING_ADDED
type: CUSTOM_ROLE_BINDING_ADDED
}
{ [-]
alternateId: /api/v1/iam/roles/WORKFLOWS_ADMIN
detailEntry: null
displayName: Workflows Administrator
id: WORKFLOWS_ADMIN
type: CUSTOM_ROLE
}
{ [-]
alternateId: /api/v1/iam/resource-sets/WORKFLOWS_IAM_POLICY
detailEntry: null
displayName: Workflows Resource Set
id: WORKFLOWS_IAM_POLICY
type: RESOURCE_SET
}
]
transaction: { [+]
}
uuid: 2c42-11f0-a9fe
version: 0
}
Any help is appreciated. Thank you!
Before anything, let me first say that when you post JSON event sample, always use "Show raw text" before copying. This helps others help you. Secondly, as @bowesmana says, it is really unclear what you are asking. You already know the value "Workflows Administrator". Do you mean to search for this value and display other related key-value pairs? Or do you mean there are other possible values from the 3rd array element of target[] that you want to know how to reach that correct array element?
If former, you need to specify which key-value pairs in that element are of interest. If latter, there are many ways, including a method that does not do "extracting" because Splunk by default has done that for you. But before doing that, you need to use Splunk's flattened-structure notation, not invented names like targetUserDisplayName. (Splunk's notation is target{}.displayName for this one.)
Anyway, assuming the latter, @bowesmana already showed you several ways. Here I first present a formulae approach to reach every JSON array node in SPL: spath + mvexpand. But before I show any code, you need to perform the most critical task: to understand how that element is different from other elements in the same array, all of them having a key displayName. In order to make this determination, you need to carefully study the data. The differentiating factor among those elements is the JSON key type in that array. So, you would be looking for the element whose type is CUSTOM_ROLE.
index=okta "debugContext.debugData.privilegeGranted"="*"
| fields - target{}.*
| spath path=target{}
| mvexpand target{}
| spath input=target{}
| where type == "CUSTOM_ROLE"
| rename actor.displayName as "Actor", displayName as "Target Name",
alternateId as "Target ID", description as "Action",
debugContext.debugData.privilegeGranted as "Role(s)"
| table Time, Actor, Action, "Target Name", "Target ID", Action, "Role(s)"
With this approach, you can handle any JSON array.
If you don't want to (re)extract everything in the array - there are occasions when mvexpand can be too expensive, here is a quirky method that can do the same thing: capture the value of target{}.displayName and target{}.alternateId corresponding to target{}.type of CUSTOM_ROLE.
index=okta "debugContext.debugData.privilegeGranted"="*"
| eval type_index = mvfind('target{}.type', "CUSTOM_ROLE")
| eval "Target Name" = mvindex('target{}.displayName', type_index)
| eval "Target ID" = mvindex('target{}.alternateId', type_index)
| rename actor.displayName as "Actor", description as "Action",
debugContext.debugData.privilegeGranted as "Role(s)"
| table Time, Actor, Action, "Target Name", "Target ID", Action, "Role(s)"
Thank you @livehybrid @yuanliu and @bowesmana! This is my first real post here, so I appreciate you bearing with me as I may not have provided a complete picture.
@yuanliu 's answer provided a clear example of how I can use mvfind and mvindex to extract the correct data. The only thing I had to add was a \b word boundary to the mvfind regex, so it wouldn't hit the earlier partial match. Here is the query:
index=okta "debugContext.debugData.privilegeGranted"="*"
| eval type_index = mvfind('target{}.type', "CUSTOM_ROLE\b")
| eval "Target Name" = mvindex('target{}.displayName', type_index)
| eval "Target ID" = mvindex('target{}.alternateId', type_index)
| rename actor.displayName as "Actor", description as "Action",
debugContext.debugData.privilegeGranted as "Role(s)"
| table Time, Actor, Action, "Target Name", "Target ID", Action, "Role(s)"
Hi @bill
If you're looking to see if the user is a Workflows Administrator then the following should work:
| eval isAdmin=IF(typeof(mvfind('target{}.displayName', "Workflows Administrator"))=="Number","Yes","No")
🌟 Did this answer help you? If so, please consider:
Your feedback encourages the volunteers in this community to continue contributing
Before anything, let me first say that when you post JSON event sample, always use "Show raw text" before copying. This helps others help you. Secondly, as @bowesmana says, it is really unclear what you are asking. You already know the value "Workflows Administrator". Do you mean to search for this value and display other related key-value pairs? Or do you mean there are other possible values from the 3rd array element of target[] that you want to know how to reach that correct array element?
If former, you need to specify which key-value pairs in that element are of interest. If latter, there are many ways, including a method that does not do "extracting" because Splunk by default has done that for you. But before doing that, you need to use Splunk's flattened-structure notation, not invented names like targetUserDisplayName. (Splunk's notation is target{}.displayName for this one.)
Anyway, assuming the latter, @bowesmana already showed you several ways. Here I first present a formulae approach to reach every JSON array node in SPL: spath + mvexpand. But before I show any code, you need to perform the most critical task: to understand how that element is different from other elements in the same array, all of them having a key displayName. In order to make this determination, you need to carefully study the data. The differentiating factor among those elements is the JSON key type in that array. So, you would be looking for the element whose type is CUSTOM_ROLE.
index=okta "debugContext.debugData.privilegeGranted"="*"
| fields - target{}.*
| spath path=target{}
| mvexpand target{}
| spath input=target{}
| where type == "CUSTOM_ROLE"
| rename actor.displayName as "Actor", displayName as "Target Name",
alternateId as "Target ID", description as "Action",
debugContext.debugData.privilegeGranted as "Role(s)"
| table Time, Actor, Action, "Target Name", "Target ID", Action, "Role(s)"
With this approach, you can handle any JSON array.
If you don't want to (re)extract everything in the array - there are occasions when mvexpand can be too expensive, here is a quirky method that can do the same thing: capture the value of target{}.displayName and target{}.alternateId corresponding to target{}.type of CUSTOM_ROLE.
index=okta "debugContext.debugData.privilegeGranted"="*"
| eval type_index = mvfind('target{}.type', "CUSTOM_ROLE")
| eval "Target Name" = mvindex('target{}.displayName', type_index)
| eval "Target ID" = mvindex('target{}.alternateId', type_index)
| rename actor.displayName as "Actor", description as "Action",
debugContext.debugData.privilegeGranted as "Role(s)"
| table Time, Actor, Action, "Target Name", "Target ID", Action, "Role(s)"
Not totally sure I understand, but if you're trying to get the 3rd array element of target which corresponds to the Workflow admin, then this little snippet will get the JSON for that array element
| eval workflow_admin=spath(_raw, "target{}")
| eval workflow_admin=mvmap(workflow_admin, if(tostring(spath('workflow_admin', "displayName"))="Workflows Administrator", 'workflow_admin', null()))
There are probably a number of ways of getting at the JSON, but this works.
Here's another way
| eval workflow_admin=json_array_to_mv(json_extract(_raw, "target{}"))
| eval workflow_admin=mvmap(workflow_admin, if(tostring(spath('workflow_admin', "displayName"))="Workflows Administrator", 'workflow_admin', null()))
Once you have workflow_admin, you can manipulate/extract the fields as needed