Files
zitadel/internal/actions/object/token.go
T
6127b567e7 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]>
2026-08-12 07:36:56 +00:00

44 lines
1.3 KiB
Go

package object
import (
"github.com/dop251/goja"
"github.com/zitadel/zitadel/internal/actions"
"github.com/zitadel/zitadel/internal/domain"
)
// TokenActorField accepts a domain.TokenActor pointer and copies its content so scripts can't mutate the domain object.
func TokenActorField(actor *domain.TokenActor) func(c *actions.FieldConfig) interface{} {
return func(c *actions.FieldConfig) interface{} {
return TokenActorFromDomain(c, actor)
}
}
// TokenActorFromDomain returns the actor of a token, in case it was obtained through
// token exchange or impersonation. It returns null when there is no actor.
func TokenActorFromDomain(c *actions.FieldConfig, actor *domain.TokenActor) goja.Value {
if actor == nil {
return c.Runtime.ToValue(nil)
}
return c.Runtime.ToValue(tokenActorFromDomain(actor))
}
// tokenActorFromDomain copies the delegation chain, so scripts can't mutate the domain object.
func tokenActorFromDomain(actor *domain.TokenActor) *tokenActor {
if actor == nil {
return nil
}
return &tokenActor{
Actor: tokenActorFromDomain(actor.Actor),
UserId: actor.UserID,
Issuer: actor.Issuer,
}
}
type tokenActor struct {
// Actor is the previous actor in the delegation chain, null if there is none.
Actor *tokenActor
UserId string
Issuer string
}