feat(oidc): provide actor information in userinfo actions (#12566)

# Which Problems Are Solved

Expose impersonating actor to `preAccessToken` and `preUserinfo`
actions.

# How the Problems Are Solved

Provide the `actor` information already present in the OIDC session
model of JWT token to the relevant actions. Both goja-based actions "v1"
and webhook based execution targets carry the actor information now.
Actor remains null in case of non-impersonated tokens. Actor may contain
nested actors to display a delegation chain of impersonators.

# Additional Changes

- dba6261c8ed0dfd00ffde6193910b1405b17432f: refactor `userinfoFlows` to
reduce complexity, add test coverage and solve a couple of potential
bugs.
- `getClientId` in actions was previously undocumented. Added to
documentation.
- A skill that reproduces manual testing using webhook.site or a local
sink.

# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/12097

---------

Co-authored-by: Claude Sonnet 5 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: Wim Van Laer <[email protected]>
This commit is contained in:
Tim Möhlmann
2026-08-12 07:36:56 +00:00
committed by GitHub
co-authored by Claude Sonnet 5 Copilot Autofix powered by AI Wim Van Laer
parent 790244dd49
commit 6127b567e7
16 changed files with 1406 additions and 141 deletions
@@ -27,32 +27,7 @@ import (
)
func setImpersonationPolicy(t *testing.T, instance *integration.Instance, value bool) {
iamCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
policy, err := instance.Client.Admin.GetSecurityPolicy(iamCTX, &admin.GetSecurityPolicyRequest{})
require.NoError(t, err)
if policy.GetPolicy().GetEnableImpersonation() != value {
_, err = instance.Client.Admin.SetSecurityPolicy(iamCTX, &admin.SetSecurityPolicyRequest{
EnableImpersonation: value,
})
require.NoError(t, err)
}
retryDuration := time.Minute
if ctxDeadline, ok := iamCTX.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t,
func(ttt *assert.CollectT) {
f, err := instance.Client.Admin.GetSecurityPolicy(iamCTX, &admin.GetSecurityPolicyRequest{})
assert.NoError(ttt, err)
if f.GetPolicy().GetEnableImpersonation() != value {
return
}
},
retryDuration,
time.Second,
"timed out waiting for ensuring impersonation policy")
instance.SetImpersonationPolicy(CTX, t, value)
}
func createMachineUserPATWithMembership(ctx context.Context, t *testing.T, instance *integration.Instance, roles ...string) (userID, pat string) {