Actions v2 - Function PreUserinfo

I'm trying to use the v2 action and move the PreUserinfo function from the v1 action, but my claims are't being set in the user. I have a webhook response in this JSON format { "set_user_metadata":[], "append_claims":[ { "key":"user_type", "value":"machine" } ], "append_log_claims":[] } Could you help me?
41 Replies
Rajat
Rajat2mo ago
hey @Mateusz Wolanowski I just tested it and it worked for me, may I know your target and how did you set it up?. I ran my server on ngrok and written a small script in go
No description
No description
No description
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
Hi @Rajat, I have the same configuration in the Zitadel console. I'm running a service with a webhook on PHP/Symfony (though I don't think the stack matters). I have tested this on our production infrastructure and also set up a local environment with Docker and Traefik. I've debugged the process in my service and tested the webhook with Postman. The responses look correct, but it's still not working.
No description
No description
No description
No description
Rajat
Rajat2mo ago
your webhook is running on http://? have you exposed it somewhere?
Rajat
Rajat2mo ago
I simulated your webhook in go
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
I'm testing on https:// and the same result
Rajat
Rajat2mo ago
what is the url?
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
Unfortunately, I can't provide the production address, the webhook is also in a larger project, so I can't share it either
Rajat
Rajat2mo ago
you can make a curl request to your webhook and see if that works, just to test if its sending the payload to zitadel you can try mine
curl -X POST https://1c71251c9f48.ngrok-free.app/webhook \
-H "Content-Type: application/json"
curl -X POST https://1c71251c9f48.ngrok-free.app/webhook \
-H "Content-Type: application/json"
I just ran it again, see it this prints the response on your end
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
ok, I try
Rajat
Rajat2mo ago
it worked! I can see here 😄 so my server is sending the payload that you see in the response json
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
i try on postman, wait, i try in ma zitadel
Rajat
Rajat2mo ago
sure
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
Do you have second logs?
Rajat
Rajat2mo ago
yes I do
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
I don't have this claim in my claims { "active": true, "scope": "openid offline_access profile email urn:zitadel:iam:org:project🆔zitadel:aud", "client_id": "332010327896031238", "token_type": "Bearer", "exp": 1754606818, "iat": 1754563618, "auth_time": 1754389519, "nbf": 1754563618, "sub": "331887565920100611", "aud": [ "332010327896031238", "332010369688076294", "332010285869039622", "331887565919641859" ], "amr": [ "pwd" ], "iss": "https://zitadel.test", "jti": "V2_332302322220662790-at_332302322220728326", "username": "zitadel-admin@zitadel.zitadel.test", "name": "ZITADEL Admin", "given_name": "ZITADEL", "family_name": "Admin", "locale": "en", "updated_at": 1754316405, "preferred_username": "zitadel-admin@zitadel.zitadel.test", "email": "zitadel-admin@zitadel.zitadel.test", "email_verified": true, "userIdentifier": "331887565920100611" }
Rajat
Rajat2mo ago
oh wow, yes, so zitadel is not sendign this claim for you what version are you on?
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
I use docker image ghcr.io/zitadel/zitadel:v4.0.0-rc.2, but on prod I use v3.3.0
Rajat
Rajat2mo ago
ah okay, I tested it on cloud v3.3.2 so it worked, I can check with my team if there's a known issue on actions v2 for that version, are you on pro tier?
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
We have a self hosting
Rajat
Rajat2mo ago
ah okay, can you upgrade?
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
to 3.3.2 or 4.0.0?
Rajat
Rajat2mo ago
you can go slow and upgrade to 3.3.2 as thren it matches with the latest cloud deployment
Mateusz Wolanowski
Mateusz WolanowskiOP2mo ago
Okay, we'll try it. Thanks, I'll be back after testing.
Ozzzkar
Ozzzkar3w ago
hey did you get this working? @Mateusz Wolanowski 🙏🏻
Mateusz Wolanowski
Hey, sorry for the delay, but I was on vacation. I have Zitadel 3.3.2 on the server and locally and claims aren't setting up. @Rajat @Ozzzkar
Ozzzkar
Ozzzkar2w ago
ohh so it's still not working
Rajat
Rajat2w ago
hey @Ozzzkar @Mateusz Wolanowski I will discuss this with my team today, will get back to you hey @Mateusz Wolanowski @Ozzzkar pls open an issue and tag me/this thread, its also not working for me https://webhook.site/#!/view/7af20ca5-fc78-4287-94be-cfd06133a39b/f2dc84bc-ff8a-4222-b2e9-3162cd698102/1
Ozzzkar
Ozzzkar2w ago
did you also test metadata or just claims? because for me, setting metadata from the PreUserinfo function seems to work as I wrote here: https://discord.com/channels/927474939156643850/1407318270226202654/1408150693419946055 so maybe it's only setting claims that doesn't work
Rajat
Rajat2w ago
hey @Ozzzkar I only tried claims as you can see, like this one, i will test metadata now, this is on v4.0.3 self hosted
Ozzzkar
Ozzzkar2w ago
because if metadata also doesn't work, you and me have inconsistencies 😄
Rajat
Rajat2w ago
seems like it tho 🤔
func webhook(w http.ResponseWriter, req *http.Request) {
// CORS (incl. preflight)
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if req.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}

// read body (optional pretty log)
body, err := io.ReadAll(req.Body)
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
defer req.Body.Close()

var pretty map[string]any
if err := json.Unmarshal(body, &pretty); err == nil {
b, _ := json.MarshalIndent(pretty, "", " ")
fmt.Println("=== RECEIVED REQUEST ===\n" + string(b) + "\n========================")
} else {
fmt.Println("=== RECEIVED RAW ===\n" + string(body) + "\n=====================")
}

// build response: add metadata + claims
resp := &Response{
SetUserMetadata: []*Metadata{
{Key: "key", Value: []byte("value")}, // example from your sample
{Key: "last_preuserinfo", Value: []byte(time.Now().UTC().Format(time.RFC3339))},
},
AppendClaims: []*AppendClaim{
{Key: "user_type", Value: "machine"}, // your original claim
{Key: "claim", Value: "value"}, // example claim
},
AppendLogClaims: []string{"log1", "log2", "log3"},
}

// write JSON
w.Header().Set("Content-Type", "application/json")
out, err := json.Marshal(resp)
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
fmt.Println("=== SENDING RESPONSE ===\n" + string(out) + "\n========================")
w.Write(out)
}
func webhook(w http.ResponseWriter, req *http.Request) {
// CORS (incl. preflight)
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if req.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}

// read body (optional pretty log)
body, err := io.ReadAll(req.Body)
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
defer req.Body.Close()

var pretty map[string]any
if err := json.Unmarshal(body, &pretty); err == nil {
b, _ := json.MarshalIndent(pretty, "", " ")
fmt.Println("=== RECEIVED REQUEST ===\n" + string(b) + "\n========================")
} else {
fmt.Println("=== RECEIVED RAW ===\n" + string(body) + "\n=====================")
}

// build response: add metadata + claims
resp := &Response{
SetUserMetadata: []*Metadata{
{Key: "key", Value: []byte("value")}, // example from your sample
{Key: "last_preuserinfo", Value: []byte(time.Now().UTC().Format(time.RFC3339))},
},
AppendClaims: []*AppendClaim{
{Key: "user_type", Value: "machine"}, // your original claim
{Key: "claim", Value: "value"}, // example claim
},
AppendLogClaims: []string{"log1", "log2", "log3"},
}

// write JSON
w.Header().Set("Content-Type", "application/json")
out, err := json.Marshal(resp)
if err != nil {
http.Error(w, "error", http.StatusInternalServerError)
return
}
fmt.Println("=== SENDING RESPONSE ===\n" + string(out) + "\n========================")
w.Write(out)
}
its sending the metadata in response BUT userinfo doesnt prints it when logging in think its a bug, or just flaky(works for you but not for me)
Mateusz Wolanowski
@Rajat But are you testing version 4.0.3 now? I rolled back to 3.3.2, which worked for you before, and it still doesn't work.
Rajat
Rajat2w ago
hey @Mateusz Wolanowski seems like it today it doesnt work, I am checking wiht my team
Mateusz Wolanowski
So now it doesnt work on 3.3.2 and 4.0.3?
Matías
Matías2w ago
Hi @Mateusz Wolanowski 👋 can you tell me if you created a target of type restCall for this Action?} I'm using this code for testing Actions v2, created a target of type restCall and Action of type Function for the preUserInfo trigger. I'm testing on cloud (Zitadel v3.4.0). The Action works for me.
Matías
Matías2w ago
No description
No description
Matías
Matías2w ago
Do you have execution logs showing that the Action code was actually executed when you logged in?
Mateusz Wolanowski
Oh no... I used Rest Webhook... now it works. Thank you very much. :gigilove:
Rajat
Rajat2w ago
good morning @Mateusz Wolanowski glad it worked out 🙂 you can mark @Matías answer with ✅ and it will auto close this thread.
Gigi the Giraffe (Zitadel)
🎉 Looks like you just helped out another community member! Thanks for being so helpful <@1354542547577344093>! You're now one step closer to leveling up—keep up the amazing peer support! 🚀

Did you find this page helpful?