mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 23:17:33 +00:00
Merge remote-tracking branch 'origin/main' into next-rc
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/database"
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/id"
|
"github.com/zitadel/zitadel/internal/id"
|
||||||
|
metrics "github.com/zitadel/zitadel/internal/telemetry/metrics/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Migration struct {
|
type Migration struct {
|
||||||
@@ -26,6 +27,7 @@ type Migration struct {
|
|||||||
|
|
||||||
Log *logging.Config
|
Log *logging.Config
|
||||||
Machine *id.Config
|
Machine *id.Config
|
||||||
|
Metrics metrics.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -40,6 +42,9 @@ func mustNewMigrationConfig(v *viper.Viper) *Migration {
|
|||||||
err := config.Log.SetLogger()
|
err := config.Log.SetLogger()
|
||||||
logging.OnError(err).Fatal("unable to set logger")
|
logging.OnError(err).Fatal("unable to set logger")
|
||||||
|
|
||||||
|
err = config.Metrics.NewMeter()
|
||||||
|
logging.OnError(err).Fatal("unable to set meter")
|
||||||
|
|
||||||
id.Configure(config.Machine)
|
id.Configure(config.Machine)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
@@ -44,7 +44,18 @@ Possible conditions for the Execution:
|
|||||||
Currently, the defined Actions v2 will be executed additionally to the defined [Actions](/concepts/features/actions).
|
Currently, the defined Actions v2 will be executed additionally to the defined [Actions](/concepts/features/actions).
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
## Migration
|
||||||
|
|
||||||
|
- [Migrate Actions v1 to Actions v2](/guides/integrate/actions/migrate-from-v1)
|
||||||
|
|
||||||
## Further reading
|
## Further reading
|
||||||
|
|
||||||
- [Actions v2 reference](/apis/actions/v2/usage)
|
- [Actions v2 reference](/guides/integrate/actions/usage)
|
||||||
- [Actions v2 example execution locally](/apis/actions/v2/testing-locally)
|
- [Actions v2 example execution for request](/guides/integrate/actions/testing-request)
|
||||||
|
- [Actions v2 example execution for request manipulation](/guides/integrate/actions/testing-request-manipulation)
|
||||||
|
- [Actions v2 example execution for request signature check](/guides/integrate/actions/testing-request-signature)
|
||||||
|
- [Actions v2 example execution for response](/guides/integrate/actions/testing-response)
|
||||||
|
- [Actions v2 example execution for response manipulation](/guides/integrate/actions/testing-response-manipulation)
|
||||||
|
- [Actions v2 example execution for function](/guides/integrate/actions/testing-function)
|
||||||
|
- [Actions v2 example execution for function manipulation](/guides/integrate/actions/testing-function-manipulation)
|
||||||
|
- [Actions v2 example execution for event](/guides/integrate/actions/testing-event)
|
114
docs/docs/guides/integrate/actions/migrate-from-v1.md
Normal file
114
docs/docs/guides/integrate/actions/migrate-from-v1.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
title: Migrate from Actions v1 to v2
|
||||||
|
---
|
||||||
|
|
||||||
|
In this guide, you will have all necessary information to migrate from Actions v1 to Actions v2 with all currently [available Flow Types](/apis/actions/introduction#available-flow-types).
|
||||||
|
|
||||||
|
## Internal Authentication
|
||||||
|
|
||||||
|
### Post Authentication
|
||||||
|
|
||||||
|
A user has authenticated directly at ZITADEL.
|
||||||
|
ZITADEL validated the users inputs for password, one-time password, security key or passwordless factor.
|
||||||
|
|
||||||
|
To react to different authentication actions, the session service, `zitadel.session.v2.SessionService`, provides the different endpoints. As a rule of thumb, use response triggers if you primarily want to handle successful and failed authentications. On the other hand, use event triggers if you need more fine-granular handling, for example by the used authentication factors.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- Handle successful authentication through the response of `/zitadel.session.v2.SessionService/CreateSession` and `/zitadel.session.v2.SessionService/SetSession`, [Action Response Example](./testing-response)
|
||||||
|
- Handle failed authentication through the response of `/zitadel.session.v2.SessionService/CreateSession` and `/zitadel.session.v2.SessionService/SetSession`, [Action Response Example](./testing-response)
|
||||||
|
- Handle session with password checked through the creation of event `session.password.checked`, [Action Event Example](./testing-event)
|
||||||
|
- Handle successful authentication through the creation of event `user.human.password.check.succeeded`, [Action Event Example](./testing-event)
|
||||||
|
- Handle failed authentication through the creation of event `user.human.password.check.failed`, [Action Event Example](./testing-event)
|
||||||
|
|
||||||
|
### Pre Creation
|
||||||
|
|
||||||
|
A user registers directly at ZITADEL.
|
||||||
|
ZITADEL did not create the user yet.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- Before a user is created through the request on `/zitadel.user.v2.UserService/AddHumanUser`, [Action Request Example](./testing-request)
|
||||||
|
- Add information to the user through the request on `/zitadel.user.v2.UserService/AddHumanUser`, [Action Request Manipulation Example](./testing-request-manipulation)
|
||||||
|
|
||||||
|
### Post Creation
|
||||||
|
|
||||||
|
A user registers directly at ZITADEL.
|
||||||
|
ZITADEL successfully created the user.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- After user is created through the response on `/zitadel.user.v2.UserService/AddHumanUser`, [Action Response Example](./testing-response)
|
||||||
|
- At the event of a user creation on `user.human.added`, [Action Event Example](./testing-event)
|
||||||
|
|
||||||
|
## External Authentication
|
||||||
|
|
||||||
|
### Post Authentication
|
||||||
|
|
||||||
|
A user has authenticated externally. ZITADEL retrieved and mapped the external information.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- Handle the information mapping from the external authentication to internal structure through the response on `/zitadel.user.v2.UserService/RetrieveIdentityProviderIntent`, [Action Response Example](./testing-response)
|
||||||
|
- information about the link to the external IDP available in the response under [`idpInformation`](/apis/resources/user_service_v2/user-service-retrieve-identity-provider-intent)
|
||||||
|
- information if a new user has to be created available in the response under [`addHumanUser`](/apis/resources/user_service_v2/user-service-retrieve-identity-provider-intent), including metadata and link to external IDP
|
||||||
|
|
||||||
|
### Pre Creation
|
||||||
|
|
||||||
|
A user registers directly at ZITADEL.
|
||||||
|
ZITADEL did not create the user yet.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- Before a user is created through the request on `/zitadel.user.v2.UserService/AddHumanUser`, [Action Request Example](./testing-request)
|
||||||
|
- Add information to the user through the request on `/zitadel.user.v2.UserService/AddHumanUser`, [Action Request Manipulation Example](./testing-request-manipulation)
|
||||||
|
|
||||||
|
### Post Creation
|
||||||
|
|
||||||
|
A user registers directly at ZITADEL.
|
||||||
|
ZITADEL successfully created the user.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- After user is created through the response on `/zitadel.user.v2.UserService/AddHumanUser`, [Action Response Example](./testing-response)
|
||||||
|
- At the event of a user creation on `user.human.added`, [Action Event Example](./testing-event)
|
||||||
|
|
||||||
|
## Complement Token
|
||||||
|
|
||||||
|
These are executed during the creation of tokens and token introspection.
|
||||||
|
|
||||||
|
### Pre Userinfo
|
||||||
|
|
||||||
|
These are called before userinfo are set in the id_token or userinfo and introspection endpoint response.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- Add claims to the userinfo through function on `preuserinfo`, [Action Function Example](./testing-function)
|
||||||
|
- Add metadata to user through function on `preuserinfo`, [Action Function Example](./testing-function)
|
||||||
|
- Add logs to the log claim through function on `preuserinfo`, [Action Function Example](./testing-function)
|
||||||
|
|
||||||
|
### Pre Access Token
|
||||||
|
|
||||||
|
These are called before the claims are set in the access token and the token type is `jwt`.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- Add claims to the userinfo through function on `preaccesstoken`, [Action Function Example](./testing-function)
|
||||||
|
- Add metadata to user through function on `preaccesstoken`, [Action Function Example](./testing-function)
|
||||||
|
- Add logs to the log claim through function on `preaccesstoken`, [Action Function Example](./testing-function)
|
||||||
|
|
||||||
|
## Customize SAML Response
|
||||||
|
|
||||||
|
These are executed before the return of the SAML Response.
|
||||||
|
|
||||||
|
### Pre SAMLResponse Creation
|
||||||
|
|
||||||
|
These are called before attributes are set in the SAMLResponse.
|
||||||
|
|
||||||
|
Some use-cases:
|
||||||
|
|
||||||
|
- Add custom attributes to the response through function on `presamlresponse`, [Action Function Example](./testing-function)
|
||||||
|
- Add metadata to user through function on `presamlresponse`, [Action Function Example](./testing-function)
|
||||||
|
|
||||||
|
|
||||||
|
|
169
docs/docs/guides/integrate/actions/testing-event.md
Normal file
169
docs/docs/guides/integrate/actions/testing-event.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
---
|
||||||
|
title: Test Actions Event
|
||||||
|
---
|
||||||
|
|
||||||
|
This guide shows you how to leverage the ZITADEL actions feature to react to events in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific event occurs.
|
||||||
|
This is useful for integrating with other systems or for triggering workflows based on events in ZITADEL.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you start, make sure you have everything set up correctly.
|
||||||
|
|
||||||
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Start example target
|
||||||
|
|
||||||
|
To test the actions feature, you need to create a target that will be called when an event occurs.
|
||||||
|
You will need to implement a listener that can receive HTTP requests and process the events.
|
||||||
|
For this example, we will use a simple Go HTTP server that will print the received events to standard output.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The signature of the received request can be checked, [please refer to the example for more information on how to](/guides/integrate/actions/testing-request-signature).
|
||||||
|
:::
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// webhook HandleFunc to read the request body and then print out the contents
|
||||||
|
func webhook(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// read the body content
|
||||||
|
sentBody, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while reading the body return an error
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
// print out the read content
|
||||||
|
fmt.Println(string(sentBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// handle the HTTP call under "/webhook"
|
||||||
|
http.HandleFunc("/webhook", webhook)
|
||||||
|
|
||||||
|
// start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090"
|
||||||
|
http.ListenAndServe(":8090", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create target
|
||||||
|
|
||||||
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as webhook, the
|
||||||
|
target can be created as follows:
|
||||||
|
|
||||||
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"name": "local webhook",
|
||||||
|
"restWebhook": {
|
||||||
|
"interruptOnError": true
|
||||||
|
},
|
||||||
|
"endpoint": "http://localhost:8090/webhook",
|
||||||
|
"timeout": "10s"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the returned ID to set in the execution.
|
||||||
|
|
||||||
|
## Set execution
|
||||||
|
|
||||||
|
To configure ZITADEL to call the target when an event occurs, you need to set an execution and define the event
|
||||||
|
condition.
|
||||||
|
|
||||||
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"condition": {
|
||||||
|
"event": {
|
||||||
|
"event": "user.human.added"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target": "<TargetID returned>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example call
|
||||||
|
|
||||||
|
Now that you have set up the target and execution, you can test it by creating a user through the Console UI or
|
||||||
|
by calling the ZITADEL API to create a human user.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"userId": {
|
||||||
|
"givenName": "Test",
|
||||||
|
"familyName": "User"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "example@test.com"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Your server should now print out something like the following. Check out
|
||||||
|
the [Sent information Event](./usage#sent-information-event) payload description.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"aggregateID": "313014806065971608",
|
||||||
|
"aggregateType": "user",
|
||||||
|
"resourceOwner": "312909075211944344",
|
||||||
|
"instanceID": "312909075211878808",
|
||||||
|
"version": "v2",
|
||||||
|
"sequence": 1,
|
||||||
|
"event_type": "user.human.added",
|
||||||
|
"created_at": "2025-03-27T10:22:43.262665+01:00",
|
||||||
|
"userID": "312909075212468632",
|
||||||
|
"event_payload": "eyJ1c2VyTmFtZSI6ImV4YW1wbGVAdGVzdC5jb20iLCJmaXJzdE5hbWUiOiJUZXN0IiwibGFzdE5hbWUiOiJVc2VyIiwiZGlzcGxheU5hbWUiOiJUZXN0IFVzZXIiLCJwcmVmZXJyZWRMYW5ndWFnZSI6InVuZCIsImVtYWlsIjoiZXhhbXBsZUB0ZXN0LmNvbSJ9"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The event_payload is base64 encoded and has the following content:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"userName": "example@test.com",
|
||||||
|
"firstName": "Test",
|
||||||
|
"lastName": "User",
|
||||||
|
"displayName": "Test User",
|
||||||
|
"preferredLanguage": "und",
|
||||||
|
"email": "example@test.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to react to events in your ZITADEL instance.
|
||||||
|
This feature can now be used to integrate with your existing systems to create custom workflows or automate tasks based on events in ZITADEL.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
@@ -0,0 +1,155 @@
|
|||||||
|
---
|
||||||
|
title: Test Actions Function Manipulation
|
||||||
|
---
|
||||||
|
|
||||||
|
This guide shows you how to leverage the ZITADEL actions feature to enhance different functions in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific functionality is used.
|
||||||
|
This is useful for integrating with other systems which need specific claims in tokens or for executing external code during OIDC or SAML flows.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you start, make sure you have everything set up correctly.
|
||||||
|
|
||||||
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Available functions
|
||||||
|
|
||||||
|
The available conditions can be found under [all available Functions](/apis/resources/action_service_v2/action-service-list-execution-functions).
|
||||||
|
|
||||||
|
## Start example target
|
||||||
|
|
||||||
|
To test the actions feature, you need to create a target that will be called when a function is used.
|
||||||
|
You will need to implement a listener that can receive HTTP requests and process the data.
|
||||||
|
For this example, we will use a simple Go HTTP server that will send back static data.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The signature of the received request can be checked, [please refer to the example for more information on how to](/guides/integrate/actions/testing-request-signature).
|
||||||
|
:::
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
SetUserMetadata []*Metadata `json:"set_user_metadata,omitempty"`
|
||||||
|
AppendClaims []*AppendClaim `json:"append_claims,omitempty"`
|
||||||
|
AppendLogClaims []string `json:"append_log_claims,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value []byte `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppendClaim struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value any `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// call HandleFunc to respond with static data
|
||||||
|
func call(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// create the response with the correct structure
|
||||||
|
resp := &Response{
|
||||||
|
SetUserMetadata: []*Metadata{
|
||||||
|
{Key: "key", Value: []byte("value")},
|
||||||
|
},
|
||||||
|
AppendClaims: []*AppendClaim{
|
||||||
|
{Key: "claim", Value: "value"},
|
||||||
|
},
|
||||||
|
AppendLogClaims: []string{"log1", "log2", "log3"},
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while marshalling the json
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// handle the HTTP call under "/call"
|
||||||
|
http.HandleFunc("/call", call)
|
||||||
|
|
||||||
|
// start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090"
|
||||||
|
http.ListenAndServe(":8090", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create target
|
||||||
|
|
||||||
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as call, the target can be created as follows:
|
||||||
|
|
||||||
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"name": "local call",
|
||||||
|
"restCall": {
|
||||||
|
"interruptOnError": true
|
||||||
|
},
|
||||||
|
"endpoint": "http://localhost:8090/call",
|
||||||
|
"timeout": "10s"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the returned ID to set in the execution.
|
||||||
|
|
||||||
|
## Set execution
|
||||||
|
|
||||||
|
To configure ZITADEL to call the target when a function is executed, you need to set an execution and define the function
|
||||||
|
condition.
|
||||||
|
|
||||||
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"condition": {
|
||||||
|
"function": {
|
||||||
|
"name": "preuserinfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target": "<TargetID returned>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example call
|
||||||
|
|
||||||
|
Now that you have set up the target and execution, you can test it by logging into Console UI or
|
||||||
|
by using any OIDC flow.
|
||||||
|
|
||||||
|
As a result 3 things happen:
|
||||||
|
- the user get the metadata with the key "key" and value "value" added
|
||||||
|
- the token has a claim "urn:zitadel:iam:claim" added with value "value"
|
||||||
|
- the token has the log claim "urn:zitadel:iam:action:preuserinfo:log" added with values "log1", "log2" and "log3".
|
||||||
|
|
||||||
|
For any further information related to [the OIDC Flow, refer to our documentation.](/guides/integrate/login/oidc/login-users)
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to react to functions in your ZITADEL instance.
|
||||||
|
This feature can now be used to integrate with your existing systems to create custom workflows or automate tasks based on functionality in ZITADEL.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
171
docs/docs/guides/integrate/actions/testing-function.md
Normal file
171
docs/docs/guides/integrate/actions/testing-function.md
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
---
|
||||||
|
title: Test Actions Function
|
||||||
|
---
|
||||||
|
|
||||||
|
This guide shows you how to leverage the ZITADEL actions feature to enhance different functions in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific functionality is used.
|
||||||
|
This is useful for integrating with other systems which need specific claims in tokens or for executing external code during OIDC or SAML flows.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you start, make sure you have everything set up correctly.
|
||||||
|
|
||||||
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Available functions
|
||||||
|
|
||||||
|
The available conditions can be found under [all available Functions](/apis/resources/action_service_v2/action-service-list-execution-functions).
|
||||||
|
|
||||||
|
## Start example target
|
||||||
|
|
||||||
|
To test the actions feature, you need to create a target that will be called when a function is used.
|
||||||
|
You will need to implement a listener that can receive HTTP requests and process the data.
|
||||||
|
For this example, we will use a simple Go HTTP server that will print the received data to standard output.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The signature of the received request can be checked, [please refer to the example for more information on how to](/guides/integrate/actions/testing-request-signature).
|
||||||
|
:::
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// webhook HandleFunc to read the request body and then print out the contents
|
||||||
|
func webhook(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// read the body content
|
||||||
|
sentBody, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while reading the body return an error
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
// print out the read content
|
||||||
|
fmt.Println(string(sentBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// handle the HTTP call under "/webhook"
|
||||||
|
http.HandleFunc("/webhook", webhook)
|
||||||
|
|
||||||
|
// start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090"
|
||||||
|
http.ListenAndServe(":8090", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create target
|
||||||
|
|
||||||
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as webhook, the target can be created as follows:
|
||||||
|
|
||||||
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"name": "local call",
|
||||||
|
"restWebhook": {
|
||||||
|
"interruptOnError": true
|
||||||
|
},
|
||||||
|
"endpoint": "http://localhost:8090/webhook",
|
||||||
|
"timeout": "10s"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the returned ID to set in the execution.
|
||||||
|
|
||||||
|
## Set execution
|
||||||
|
|
||||||
|
To configure ZITADEL to call the target when a function is executed, you need to set an execution and define the function
|
||||||
|
condition.
|
||||||
|
|
||||||
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"condition": {
|
||||||
|
"function": {
|
||||||
|
"name": "preuserinfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target": "<TargetID returned>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example call
|
||||||
|
|
||||||
|
Now that you have set up the target and execution, you can test it by logging into Console UI or
|
||||||
|
by using any OIDC flow.
|
||||||
|
|
||||||
|
Your server should now print out something like the following. Check out the [Sent information Function](./usage#sent-information-function) payload description.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"function" : "function/preuserinfo",
|
||||||
|
"userinfo" : {
|
||||||
|
"sub" : "312909075212468632"
|
||||||
|
},
|
||||||
|
"user" : {
|
||||||
|
"id" : "312909075212468632",
|
||||||
|
"creation_date" : "2025-03-26T15:52:23.917636Z",
|
||||||
|
"change_date" : "2025-03-26T15:52:23.917636Z",
|
||||||
|
"resource_owner" : "312909075211944344",
|
||||||
|
"sequence" : 2,
|
||||||
|
"state" : 1,
|
||||||
|
"username" : "user@example.com",
|
||||||
|
"preferred_login_name" : "zitadel@zitadel.localhost",
|
||||||
|
"human" : {
|
||||||
|
"first_name" : "Example firstname",
|
||||||
|
"last_name" : "Example lastname",
|
||||||
|
"display_name" : "Example displayname",
|
||||||
|
"preferred_language" : "en",
|
||||||
|
"email" : "user@example.com",
|
||||||
|
"is_email_verified" : true,
|
||||||
|
"password_changed" : "0001-01-01T00:00:00Z",
|
||||||
|
"mfa_init_skipped" : "0001-01-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_metadata" : [ {
|
||||||
|
"creation_date" : "2025-03-27T09:10:25.879677Z",
|
||||||
|
"change_date" : "2025-03-27T09:10:25.879677Z",
|
||||||
|
"resource_owner" : "312909075211944344",
|
||||||
|
"sequence" : 18,
|
||||||
|
"key" : "key",
|
||||||
|
"value" : "dmFsdWU="
|
||||||
|
} ],
|
||||||
|
"org" : {
|
||||||
|
"id" : "312909075211944344",
|
||||||
|
"name" : "ZITADEL",
|
||||||
|
"primary_domain" : "example.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For any further information related to [the OIDC Flow, refer to our documentation.](/guides/integrate/login/oidc/login-users)
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to react to functions in your ZITADEL instance.
|
||||||
|
This feature can now be used to customize the functionality in ZITADEL, in particular the content of the OIDC tokens and SAML responses.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
@@ -0,0 +1,188 @@
|
|||||||
|
---
|
||||||
|
title: Test Actions Request Manipulation
|
||||||
|
---
|
||||||
|
|
||||||
|
This guide shows you how to leverage the ZITADEL actions feature to manipulate API requests in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific API request occurs.
|
||||||
|
This is useful for adding information to managed resources in ZITADEL.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you start, make sure you have everything set up correctly.
|
||||||
|
|
||||||
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Start example target
|
||||||
|
|
||||||
|
To test the actions feature, you need to create a target that will be called when an API endpoint is called.
|
||||||
|
You will need to implement a listener that can receive HTTP requests, process the request and returns the manipulated request.
|
||||||
|
For this example, we will use a simple Go HTTP server that will return the request with added metadata.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The signature of the received request can be checked, [please refer to the example for more information on how to](/guides/integrate/actions/testing-request-signature).
|
||||||
|
:::
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contextRequest struct {
|
||||||
|
Request *user.AddHumanUserRequest `json:"request"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// call HandleFunc to read the request body, manipulate the content and return the manipulated request
|
||||||
|
func call(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// read the body content
|
||||||
|
sentBody, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while reading the body return an error
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
|
||||||
|
// read the request into the expected structure
|
||||||
|
request := new(contextRequest)
|
||||||
|
if err := json.Unmarshal(sentBody, request); err != nil {
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the response from the received request
|
||||||
|
response := request.Request
|
||||||
|
// manipulate the request to send back as response
|
||||||
|
if response.Metadata == nil {
|
||||||
|
response.Metadata = make([]*user.SetMetadataEntry, 0)
|
||||||
|
}
|
||||||
|
response.Metadata = append(response.Metadata, &user.SetMetadataEntry{Key: "organization", Value: []byte("company")})
|
||||||
|
|
||||||
|
// marshal the request into json
|
||||||
|
data, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while marshalling the json
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the manipulated request
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// handle the HTTP call under "/call"
|
||||||
|
http.HandleFunc("/call", call)
|
||||||
|
|
||||||
|
// start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090"
|
||||||
|
http.ListenAndServe(":8090", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create target
|
||||||
|
|
||||||
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as call, the target can be created as follows:
|
||||||
|
|
||||||
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"name": "local call",
|
||||||
|
"restCall": {
|
||||||
|
"interruptOnError": true
|
||||||
|
},
|
||||||
|
"endpoint": "http://localhost:8090/call",
|
||||||
|
"timeout": "10s"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the returned ID to set in the execution.
|
||||||
|
|
||||||
|
## Set execution
|
||||||
|
|
||||||
|
To call the target just created before, with the intention to manipulate the request used for user creation by the user V2 API, we define an execution with a method condition.
|
||||||
|
|
||||||
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"condition": {
|
||||||
|
"request": {
|
||||||
|
"method": "/zitadel.user.v2.UserService/AddHumanUser"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target": "<TargetID returned>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example call
|
||||||
|
|
||||||
|
Now that you have set up the target and execution, you can test it by creating a user through the Console UI or
|
||||||
|
by calling the ZITADEL API to create a human user.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"profile": {
|
||||||
|
"givenName": "Example_given",
|
||||||
|
"familyName": "Example_family"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "example@example.com"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Your server should now manipulate the request to something like the following. Check out
|
||||||
|
the [Sent information Request](./usage#sent-information-request) payload description.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"profile": {
|
||||||
|
"givenName": "Example_given",
|
||||||
|
"familyName": "Example_family"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "example@example.com"
|
||||||
|
}
|
||||||
|
"metadata": [
|
||||||
|
{"key": "organization", "value": "Y29tcGFueQ=="}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to manipulate API requests in your ZITADEL instance.
|
||||||
|
This feature can now be used to add or manipulate information to managed resources in ZITADEL.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
@@ -1,8 +1,10 @@
|
|||||||
---
|
---
|
||||||
title: Test Actions Locally
|
title: Test Actions Request Signature Check
|
||||||
---
|
---
|
||||||
|
|
||||||
In this guide, you will create a ZITADEL execution and target. After a user is created through the API, the target is called.
|
This guide shows you how to leverage the ZITADEL actions feature to react to API requests in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific API request occurs.
|
||||||
|
This is useful for information provisioning in between systems or for triggering workflows based on API requests in ZITADEL.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -11,9 +13,17 @@ Before you start, make sure you have everything set up correctly.
|
|||||||
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
- Your ZITADEL instance needs to have the actions feature enabled.
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
## Start example target
|
## Start example target
|
||||||
|
|
||||||
To start a simple HTTP server locally, which receives the webhook call, the following code example can be used:
|
To test the actions feature, you need to create a target that will be called when an API endpoint is called.
|
||||||
|
You will need to implement a listener that can receive HTTP requests, check the signature and process the request.
|
||||||
|
For this example, we will use a simple Go HTTP server that will print the received request to standard output.
|
||||||
|
The 'signingKey' is the key received in the next step 'Create target'.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
@@ -22,8 +32,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/pkg/actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const signingKey = "somekey"
|
||||||
|
|
||||||
// webhook HandleFunc to read the request body and then print out the contents
|
// webhook HandleFunc to read the request body and then print out the contents
|
||||||
func webhook(w http.ResponseWriter, req *http.Request) {
|
func webhook(w http.ResponseWriter, req *http.Request) {
|
||||||
// read the body content
|
// read the body content
|
||||||
@@ -33,6 +47,13 @@ func webhook(w http.ResponseWriter, req *http.Request) {
|
|||||||
http.Error(w, "error", http.StatusInternalServerError)
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
// validate signature
|
||||||
|
if err := actions.ValidatePayload(sentBody, req.Header.Get(actions.SigningHeader), signingKey); err != nil {
|
||||||
|
// if the signed content is not equal the sent content return an error
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
// print out the read content
|
// print out the read content
|
||||||
fmt.Println(string(sentBody))
|
fmt.Println(string(sentBody))
|
||||||
}
|
}
|
||||||
@@ -46,27 +67,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
What happens here is only a target which prints out the received request, which could also be handled with a different logic.
|
|
||||||
|
|
||||||
### Check Signature
|
|
||||||
|
|
||||||
To additionally check the signature header you can add the following to the example:
|
|
||||||
```go
|
|
||||||
// validate signature
|
|
||||||
if err := actions.ValidatePayload(sentBody, req.Header.Get(actions.SigningHeader), signingKey); err != nil {
|
|
||||||
// if the signed content is not equal the sent content return an error
|
|
||||||
http.Error(w, "error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Where you can replace 'signingKey' with the key received in the next step 'Create target'.
|
|
||||||
|
|
||||||
## Create target
|
## Create target
|
||||||
|
|
||||||
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as webhook, the target can be created as follows:
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as webhook, the target can be created as follows:
|
||||||
|
|
||||||
[Create a target](/apis/resources/action_service_v2/action-service-create-target)
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
@@ -87,9 +92,10 @@ Save the returned ID to set in the execution.
|
|||||||
|
|
||||||
## Set execution
|
## Set execution
|
||||||
|
|
||||||
To call the target just created before, with the intention to print the request used for user creation by the user V2 API, we define an execution with a method condition.
|
To configure ZITADEL to call the target when an API endpoint is called, you need to set an execution and define the request
|
||||||
|
condition.
|
||||||
|
|
||||||
[Set an execution](/apis/resources/action_service_v2/action-service-set-execution)
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
@@ -112,7 +118,8 @@ curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
|||||||
|
|
||||||
## Example call
|
## Example call
|
||||||
|
|
||||||
Now on every call on `/zitadel.user.v2.UserService/AddHumanUser` the local server prints out the received body of the request:
|
Now that you have set up the target and execution, you can test it by creating a user through the Console UI or
|
||||||
|
by calling the ZITADEL API to create a human user.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
||||||
@@ -130,7 +137,9 @@ curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
|||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
Should print out something like, also described under [Sent information Request](./usage#sent-information-request):
|
Your server should now print out something like the following. Check out
|
||||||
|
the [Sent information Request](./usage#sent-information-request) payload description.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
{
|
{
|
||||||
"fullMethod": "/zitadel.user.v2.UserService/AddHumanUser",
|
"fullMethod": "/zitadel.user.v2.UserService/AddHumanUser",
|
||||||
@@ -150,4 +159,9 @@ Should print out something like, also described under [Sent information Request]
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to react to API requests in your ZITADEL instance.
|
||||||
|
This feature can now be used to provision information in between systems or for triggering workflows based on API requests in ZITADEL.
|
||||||
|
Additionally, you are sure that the request was not tempered with, as the signature was created with the combination of signing key and payload.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
159
docs/docs/guides/integrate/actions/testing-request.md
Normal file
159
docs/docs/guides/integrate/actions/testing-request.md
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
---
|
||||||
|
title: Test Actions Request
|
||||||
|
---
|
||||||
|
|
||||||
|
This guide shows you how to leverage the ZITADEL actions feature to react to API requests in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific API request occurs.
|
||||||
|
This is useful for information provisioning in between systems or for triggering workflows based on API requests in ZITADEL.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you start, make sure you have everything set up correctly.
|
||||||
|
|
||||||
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Start example target
|
||||||
|
|
||||||
|
To test the actions feature, you need to create a target that will be called when an API endpoint is called.
|
||||||
|
You will need to implement a listener that can receive HTTP requests and process the request.
|
||||||
|
For this example, we will use a simple Go HTTP server that will print the received request to standard output.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The signature of the received request can be checked, [please refer to the example for more information on how to](/guides/integrate/actions/testing-request-signature).
|
||||||
|
:::
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// webhook HandleFunc to read the request body and then print out the contents
|
||||||
|
func webhook(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// read the body content
|
||||||
|
sentBody, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while reading the body return an error
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
// print out the read content
|
||||||
|
fmt.Println(string(sentBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// handle the HTTP call under "/webhook"
|
||||||
|
http.HandleFunc("/webhook", webhook)
|
||||||
|
|
||||||
|
// start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090"
|
||||||
|
http.ListenAndServe(":8090", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create target
|
||||||
|
|
||||||
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as webhook, the target can be created as follows:
|
||||||
|
|
||||||
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"name": "local webhook",
|
||||||
|
"restWebhook": {
|
||||||
|
"interruptOnError": true
|
||||||
|
},
|
||||||
|
"endpoint": "http://localhost:8090/webhook",
|
||||||
|
"timeout": "10s"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the returned ID to set in the execution.
|
||||||
|
|
||||||
|
## Set execution
|
||||||
|
|
||||||
|
To configure ZITADEL to call the target when an API endpoint is called, you need to set an execution and define the request
|
||||||
|
condition.
|
||||||
|
|
||||||
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"condition": {
|
||||||
|
"request": {
|
||||||
|
"method": "/zitadel.user.v2.UserService/AddHumanUser"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target": "<TargetID returned>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example call
|
||||||
|
|
||||||
|
Now that you have set up the target and execution, you can test it by creating a user through the Console UI or
|
||||||
|
by calling the ZITADEL API to create a human user.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"profile": {
|
||||||
|
"givenName": "Test",
|
||||||
|
"familyName": "User"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "example@test.com"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Your server should now print out something like the following. Check out
|
||||||
|
the [Sent information Request](./usage#sent-information-request) payload description.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
{
|
||||||
|
"fullMethod": "/zitadel.user.v2.UserService/AddHumanUser",
|
||||||
|
"instanceID": "262851882718855632",
|
||||||
|
"orgID": "262851882718921168",
|
||||||
|
"projectID": "262851882719052240",
|
||||||
|
"userID": "262851882718986704",
|
||||||
|
"request": {
|
||||||
|
"profile": {
|
||||||
|
"given_name": "Test",
|
||||||
|
"family_name": "User"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "example@test.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to react to API requests in your ZITADEL instance.
|
||||||
|
This feature can now be used to provision information in between systems or for triggering workflows based on API requests in ZITADEL.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
@@ -0,0 +1,254 @@
|
|||||||
|
---
|
||||||
|
title: Test Actions Response Manipulation
|
||||||
|
---
|
||||||
|
|
||||||
|
This guide shows you how to leverage the ZITADEL actions feature to manipulate API responses in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific API response occurs.
|
||||||
|
This is useful for triggering workflows based on API responses in ZITADEL. You can even use this to provide data necessary data to the new login UI as shown in this example.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you start, make sure you have everything set up correctly.
|
||||||
|
|
||||||
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Start example target
|
||||||
|
|
||||||
|
To test the actions feature, you need to create a target that will be called when an API endpoint is called.
|
||||||
|
You will need to implement a listener that can receive HTTP requests, process the request and returns the manipulated request.
|
||||||
|
For this example, we will use a simple Go HTTP server that will return the request with added metadata.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The signature of the received request can be checked, [please refer to the example for more information on how to](/guides/integrate/actions/testing-request-signature).
|
||||||
|
:::
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type response struct {
|
||||||
|
Request *user.RetrieveIdentityProviderIntentRequest `json:"request"`
|
||||||
|
Response *user.RetrieveIdentityProviderIntentResponse `json:"response"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// call HandleFunc to read the response body, manipulate the content and return the response
|
||||||
|
func call(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// read the body content
|
||||||
|
sentBody, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while reading the body return an error
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
|
||||||
|
// read the response into the expected structure
|
||||||
|
request := new(response)
|
||||||
|
if err := json.Unmarshal(sentBody, request); err != nil {
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the response from the received response
|
||||||
|
resp := request.Response
|
||||||
|
// manipulate the received response to send back as response
|
||||||
|
if resp != nil && resp.AddHumanUser != nil {
|
||||||
|
// manipulate the response
|
||||||
|
resp.AddHumanUser.Metadata = append(resp.AddHumanUser.Metadata, &user.SetMetadataEntry{Key: "organization", Value: []byte("company")})
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal the response into json
|
||||||
|
data, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while marshalling the json
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the manipulated response
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// handle the HTTP call under "/call"
|
||||||
|
http.HandleFunc("/call", call)
|
||||||
|
|
||||||
|
// start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090"
|
||||||
|
http.ListenAndServe(":8090", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create target
|
||||||
|
|
||||||
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as call, the
|
||||||
|
target can be created as follows:
|
||||||
|
|
||||||
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"name": "local call",
|
||||||
|
"restCall": {
|
||||||
|
"interruptOnError": true
|
||||||
|
},
|
||||||
|
"endpoint": "http://localhost:8090/call",
|
||||||
|
"timeout": "10s"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the returned ID to set in the execution.
|
||||||
|
|
||||||
|
## Set execution
|
||||||
|
|
||||||
|
To call the target just created before, with the intention to manipulate the retrieve of an intent by the user V2 API,
|
||||||
|
we define an execution with a response condition.
|
||||||
|
|
||||||
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"condition": {
|
||||||
|
"response": {
|
||||||
|
"method": "/zitadel.user.v2.UserService/RetrieveIdentityProviderIntent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target": "<TargetID returned>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example call
|
||||||
|
|
||||||
|
Now that you have set up the target and execution, you can test it by using a login-flow in the typescript login with an external IDP.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"sequence": "599",
|
||||||
|
"changeDate": "2023-06-15T06:44:26.039444Z",
|
||||||
|
"resourceOwner": "163840776835432705"
|
||||||
|
},
|
||||||
|
"idpInformation": {
|
||||||
|
"oauth": {
|
||||||
|
"accessToken": "ya29...",
|
||||||
|
"idToken": "ey..."
|
||||||
|
},
|
||||||
|
"idpId": "218528353504723201",
|
||||||
|
"userId": "218528353504723202",
|
||||||
|
"username": "test-user@localhost",
|
||||||
|
"rawInformation": {
|
||||||
|
"User": {
|
||||||
|
"email": "test-user@localhost",
|
||||||
|
"email_verified": true,
|
||||||
|
"family_name": "User",
|
||||||
|
"given_name": "Test",
|
||||||
|
"hd": "mouse.com",
|
||||||
|
"locale": "de",
|
||||||
|
"name": "Minnie Mouse",
|
||||||
|
"picture": "https://lh3.googleusercontent.com/a/AAcKTtf973Q7NH8KzKTMEZELPU9lx45WpQ9FRBuxFdPb=s96-c",
|
||||||
|
"sub": "111392805975715856637"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addHumanUser": {
|
||||||
|
"idpLinks": [
|
||||||
|
{"idpId": "218528353504723201", "userId": "218528353504723202", "userName": "test-user@localhost"}
|
||||||
|
],
|
||||||
|
"username": "test-user@localhost",
|
||||||
|
"profile": {
|
||||||
|
"givenName": "Test",
|
||||||
|
"familyName": "User",
|
||||||
|
"displayName": "Test User",
|
||||||
|
"preferredLanguage": "de"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "test-user@zitadel.ch",
|
||||||
|
"isVerified": true
|
||||||
|
},
|
||||||
|
"metadata": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Your server should now manipulate the response to something like the following. Check out
|
||||||
|
the [Sent information Response](./usage#sent-information-response) payload description.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"sequence": "599",
|
||||||
|
"changeDate": "2023-06-15T06:44:26.039444Z",
|
||||||
|
"resourceOwner": "163840776835432705"
|
||||||
|
},
|
||||||
|
"idpInformation": {
|
||||||
|
"oauth": {
|
||||||
|
"accessToken": "ya29...",
|
||||||
|
"idToken": "ey..."
|
||||||
|
},
|
||||||
|
"idpId": "218528353504723201",
|
||||||
|
"userId": "218528353504723202",
|
||||||
|
"username": "test-user@localhost",
|
||||||
|
"rawInformation": {
|
||||||
|
"User": {
|
||||||
|
"email": "test-user@localhost",
|
||||||
|
"email_verified": true,
|
||||||
|
"family_name": "User",
|
||||||
|
"given_name": "Test",
|
||||||
|
"hd": "mouse.com",
|
||||||
|
"locale": "de",
|
||||||
|
"name": "Minnie Mouse",
|
||||||
|
"picture": "https://lh3.googleusercontent.com/a/AAcKTtf973Q7NH8KzKTMEZELPU9lx45WpQ9FRBuxFdPb=s96-c",
|
||||||
|
"sub": "111392805975715856637"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addHumanUser": {
|
||||||
|
"idpLinks": [
|
||||||
|
{"idpId": "218528353504723201", "userId": "218528353504723202", "userName": "test-user@localhost"}
|
||||||
|
],
|
||||||
|
"username": "test-user@localhost",
|
||||||
|
"profile": {
|
||||||
|
"givenName": "Test",
|
||||||
|
"familyName": "User",
|
||||||
|
"displayName": "Test User",
|
||||||
|
"preferredLanguage": "de"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "test-user@zitadel.ch",
|
||||||
|
"isVerified": true
|
||||||
|
},
|
||||||
|
"metadata": [
|
||||||
|
{"key": "organization", "value": "Y29tcGFueQ=="}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to manipulate API responses in your ZITADEL instance.
|
||||||
|
This feature can now be used to add necessary information for clients including the new login UI.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
167
docs/docs/guides/integrate/actions/testing-response.md
Normal file
167
docs/docs/guides/integrate/actions/testing-response.md
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
---
|
||||||
|
title: Test Actions Response
|
||||||
|
---
|
||||||
|
|
||||||
|
This guide shows you how to leverage the ZITADEL actions feature to react to API responses in your ZITADEL instance.
|
||||||
|
You can use the actions feature to create a target that will be called when a specific API response occurs.
|
||||||
|
This is useful for information provisioning in between systems or for triggering workflows based on API responses in ZITADEL.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you start, make sure you have everything set up correctly.
|
||||||
|
|
||||||
|
- You need to be at least a ZITADEL [_IAM_OWNER_](/guides/manage/console/managers)
|
||||||
|
- Your ZITADEL instance needs to have the actions feature enabled.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that this guide assumes that ZITADEL is running on the same machine as the target and can be reached via `localhost`.
|
||||||
|
In case you are using a different setup, you need to adjust the target URL accordingly and will need to make sure that the target is reachable from ZITADEL.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Start example target
|
||||||
|
|
||||||
|
To test the actions feature, you need to create a target that will be called when an API endpoint is called.
|
||||||
|
You will need to implement a listener that can receive HTTP requests and process the request.
|
||||||
|
For this example, we will use a simple Go HTTP server that will print the received request to standard output.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The signature of the received request can be checked, [please refer to the example for more information on how to](/guides/integrate/actions/testing-request-signature).
|
||||||
|
:::
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// webhook HandleFunc to read the request body and then print out the contents
|
||||||
|
func webhook(w http.ResponseWriter, req *http.Request) {
|
||||||
|
// read the body content
|
||||||
|
sentBody, err := io.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
// if there was an error while reading the body return an error
|
||||||
|
http.Error(w, "error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer req.Body.Close()
|
||||||
|
// print out the read content
|
||||||
|
fmt.Println(string(sentBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// handle the HTTP call under "/webhook"
|
||||||
|
http.HandleFunc("/webhook", webhook)
|
||||||
|
|
||||||
|
// start an HTTP server with the before defined function to handle the endpoint under "http://localhost:8090"
|
||||||
|
http.ListenAndServe(":8090", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create target
|
||||||
|
|
||||||
|
As you see in the example above the target is created with HTTP and port '8090' and if we want to use it as webhook, the target can be created as follows:
|
||||||
|
|
||||||
|
See [Create a target](/apis/resources/action_service_v2/action-service-create-target) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X POST 'https://$CUSTOM-DOMAIN/v2beta/actions/targets' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"name": "local webhook",
|
||||||
|
"restWebhook": {
|
||||||
|
"interruptOnError": true
|
||||||
|
},
|
||||||
|
"endpoint": "http://localhost:8090/webhook",
|
||||||
|
"timeout": "10s"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Save the returned ID to set in the execution.
|
||||||
|
|
||||||
|
## Set execution
|
||||||
|
|
||||||
|
To configure Zitadel to call the target when an API endpoint is called, you need to set an execution and define the response
|
||||||
|
condition.
|
||||||
|
|
||||||
|
See [Set an execution](/apis/resources/action_service_v2/action-service-set-execution) for more detailed information.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2beta/actions/executions' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"condition": {
|
||||||
|
"response": {
|
||||||
|
"method": "/zitadel.user.v2.UserService/AddHumanUser"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target": "<TargetID returned>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example call
|
||||||
|
|
||||||
|
Now that you have set up the target and execution, you can test it by creating a user through the Console UI or
|
||||||
|
by calling the ZITADEL API to create a human user.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -L -X PUT 'https://$CUSTOM-DOMAIN/v2/users/human' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json' \
|
||||||
|
-H 'Authorization: Bearer <TOKEN>' \
|
||||||
|
--data-raw '{
|
||||||
|
"userId": {
|
||||||
|
"givenName": "Example_given",
|
||||||
|
"familyName": "Example_family"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "example@example.com"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Your server should now print out something like the following. Check out
|
||||||
|
the [Sent information Response](./usage#sent-information-response) payload description.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"fullMethod": "/zitadel.user.v2.UserService/AddHumanUser",
|
||||||
|
"instanceID": "262851882718855632",
|
||||||
|
"orgID": "262851882718921168",
|
||||||
|
"projectID": "262851882719052240",
|
||||||
|
"userID": "262851882718986704",
|
||||||
|
"request": {
|
||||||
|
"profile": {
|
||||||
|
"given_name": "Example_given",
|
||||||
|
"family_name": "Example_family"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"email": "example@example.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"user_id": "312918757460672920",
|
||||||
|
"details": {
|
||||||
|
"sequence": "2",
|
||||||
|
"change_date": "2025-03-26T17:28:33.856436Z",
|
||||||
|
"resource_owner": "312909075211944344",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
You have successfully set up a target and execution to react to API responses in your ZITADEL instance.
|
||||||
|
This feature can now be used to provision information in between systems or for triggering workflows based on API responses in ZITADEL.
|
||||||
|
Find more information about the actions feature in the [API documentation](/concepts/features/actions_v2).
|
@@ -30,7 +30,9 @@ The information sent to the Endpoint is structured as JSON:
|
|||||||
"orgID": "ID of the organization related to the calling context",
|
"orgID": "ID of the organization related to the calling context",
|
||||||
"projectID": "ID of the project related to the used application",
|
"projectID": "ID of the project related to the used application",
|
||||||
"userID": "ID of the calling user",
|
"userID": "ID of the calling user",
|
||||||
"request": "full request of the call"
|
"request": {
|
||||||
|
"attribute": "Attribute value of full request of the call"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,8 +47,298 @@ The information sent to the Endpoint is structured as JSON:
|
|||||||
"orgID": "ID of the organization related to the calling context",
|
"orgID": "ID of the organization related to the calling context",
|
||||||
"projectID": "ID of the project related to the used application",
|
"projectID": "ID of the project related to the used application",
|
||||||
"userID": "ID of the calling user",
|
"userID": "ID of the calling user",
|
||||||
"request": "full request of the call",
|
"request": {
|
||||||
"response": "full response of the call"
|
"attribute": "Attribute value of full request of the call"
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"attribute": "Attribute value of full response of the call"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sent information Function
|
||||||
|
|
||||||
|
Information sent and expected back are specific to the function.
|
||||||
|
|
||||||
|
#### PreUserinfo
|
||||||
|
|
||||||
|
The information sent to the Endpoint is structured as JSON:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"function": "Name of the function",
|
||||||
|
"userinfo": {
|
||||||
|
"given_name": "",
|
||||||
|
"family_name": "",
|
||||||
|
"middle_name": "",
|
||||||
|
"nickname": "",
|
||||||
|
"profile": "",
|
||||||
|
"picture": "",
|
||||||
|
...
|
||||||
|
"preferred_username": "",
|
||||||
|
"email": "",
|
||||||
|
"email_verified": true,
|
||||||
|
"phone_number": "",
|
||||||
|
"phone_number_verified": true
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"id": "",
|
||||||
|
"creation_date": "",
|
||||||
|
...
|
||||||
|
"human": {
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": "",
|
||||||
|
...
|
||||||
|
"email": "",
|
||||||
|
"is_email_verified": true,
|
||||||
|
"phone": "",
|
||||||
|
"is_phone_verified": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_metadata": [
|
||||||
|
{
|
||||||
|
"creation_date": "",
|
||||||
|
"change_date": "",
|
||||||
|
"resource_owner": "",
|
||||||
|
"sequence": "",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"org": {
|
||||||
|
"id": "ID of the organization the user belongs to",
|
||||||
|
"name": "Name of the organization the user belongs to",
|
||||||
|
"primary_domain": "Primary domain of the organization the user belongs to"
|
||||||
|
},
|
||||||
|
"user_grants": [
|
||||||
|
{
|
||||||
|
"id": "",
|
||||||
|
"projectGrantId": "The ID of the project grant",
|
||||||
|
"state": 1,
|
||||||
|
"creationDate": "",
|
||||||
|
"changeDate": "",
|
||||||
|
"sequence": 1,
|
||||||
|
"userId": "",
|
||||||
|
"roles": [
|
||||||
|
"role"
|
||||||
|
],
|
||||||
|
"userResourceOwner": "The ID of the organization the user belongs to",
|
||||||
|
"userGrantResourceOwner": "The ID of the organization the user got authorization granted",
|
||||||
|
"userGrantResourceOwnerName": "The name of the organization the user got authorization granted",
|
||||||
|
"projectId": "",
|
||||||
|
"projectName": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The expected structure of the JSON as response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"set_user_metadata": [
|
||||||
|
{
|
||||||
|
"key": "key of metadata to be set on the user",
|
||||||
|
"value": "base64 value of metadata to be set on the user"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"append_claims": [
|
||||||
|
{
|
||||||
|
"key": "key of claim to be set on the user",
|
||||||
|
"value": "value of claim to be set on the user"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"append_log_claims": [
|
||||||
|
"Log to be appended to the log claim on the token"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### PreAccessToken
|
||||||
|
|
||||||
|
The information sent to the Endpoint is structured as JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"function": "Name of the function",
|
||||||
|
"userinfo": {
|
||||||
|
"given_name": "",
|
||||||
|
"family_name": "",
|
||||||
|
"middle_name": "",
|
||||||
|
"nickname": "",
|
||||||
|
"profile": "",
|
||||||
|
"picture": "",
|
||||||
|
...
|
||||||
|
"preferred_username": "",
|
||||||
|
"email": "",
|
||||||
|
"email_verified": true/false,
|
||||||
|
"phone_number": "",
|
||||||
|
"phone_number_verified": true/false
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"id": "",
|
||||||
|
"creation_date": "",
|
||||||
|
...
|
||||||
|
"human": {
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": "",
|
||||||
|
...
|
||||||
|
"email": "",
|
||||||
|
"is_email_verified": true,
|
||||||
|
"phone": "",
|
||||||
|
"is_phone_verified": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_metadata": [
|
||||||
|
{
|
||||||
|
"creation_date": "",
|
||||||
|
"change_date": "",
|
||||||
|
"resource_owner": "",
|
||||||
|
"sequence": "",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"org": {
|
||||||
|
"id": "ID of the organization the user belongs to",
|
||||||
|
"name": "Name of the organization the user belongs to",
|
||||||
|
"primary_domain": "Primary domain of the organization the user belongs to"
|
||||||
|
},
|
||||||
|
"user_grants": [
|
||||||
|
{
|
||||||
|
"id": "",
|
||||||
|
"projectGrantId": "The ID of the project grant",
|
||||||
|
"state": 1,
|
||||||
|
"creationDate": "",
|
||||||
|
"changeDate": "",
|
||||||
|
"sequence": 1,
|
||||||
|
"userId": "",
|
||||||
|
"roles": [
|
||||||
|
"role"
|
||||||
|
],
|
||||||
|
"userResourceOwner": "The ID of the organization the user belongs to",
|
||||||
|
"userGrantResourceOwner": "The ID of the organization the user got authorization granted",
|
||||||
|
"userGrantResourceOwnerName": "The name of the organization the user got authorization granted",
|
||||||
|
"projectId": "",
|
||||||
|
"projectName": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The expected structure of the JSON as response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"set_user_metadata": [
|
||||||
|
{
|
||||||
|
"key": "key of metadata to be set on the user",
|
||||||
|
"value": "base64 value of metadata to be set on the user"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"append_claims": [
|
||||||
|
{
|
||||||
|
"key": "key of claim to be set on the user",
|
||||||
|
"value": "value of claim to be set on the user"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"append_log_claims": [
|
||||||
|
"Log to be appended to the log claim on the token"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### PreSAMLResponse
|
||||||
|
|
||||||
|
The information sent to the Endpoint is structured as JSON:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"function": "Name of the function",
|
||||||
|
"userinfo": {
|
||||||
|
"given_name": "",
|
||||||
|
"family_name": "",
|
||||||
|
"middle_name": "",
|
||||||
|
"nickname": "",
|
||||||
|
"profile": "",
|
||||||
|
"picture": "",
|
||||||
|
...
|
||||||
|
"preferred_username": "",
|
||||||
|
"email": "",
|
||||||
|
"email_verified": true,
|
||||||
|
"phone_number": "",
|
||||||
|
"phone_number_verified": true
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"id": "",
|
||||||
|
"creation_date": "",
|
||||||
|
...
|
||||||
|
"human": {
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": "",
|
||||||
|
...
|
||||||
|
"email": "",
|
||||||
|
"is_email_verified": true,
|
||||||
|
"phone": "",
|
||||||
|
"is_phone_verified": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_grants": [
|
||||||
|
{
|
||||||
|
"id": "",
|
||||||
|
"projectGrantId": "The ID of the project grant",
|
||||||
|
"state": 1,
|
||||||
|
"creationDate": "",
|
||||||
|
"changeDate": "",
|
||||||
|
"sequence": 1,
|
||||||
|
"userId": "",
|
||||||
|
"roles": [
|
||||||
|
"role"
|
||||||
|
],
|
||||||
|
"userResourceOwner": "The ID of the organization the user belongs to",
|
||||||
|
"userGrantResourceOwner": "The ID of the organization the user got authorization granted",
|
||||||
|
"userGrantResourceOwnerName": "The name of the organization the user got authorization granted",
|
||||||
|
"projectId": "",
|
||||||
|
"projectName": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The expected structure of the JSON as response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"set_user_metadata": [
|
||||||
|
{
|
||||||
|
"key": "key of metadata to be set on the user",
|
||||||
|
"value": "base64 value of metadata to be set on the user"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"append_attribute": [
|
||||||
|
{
|
||||||
|
"name": "name of the attribute to be added to the response",
|
||||||
|
"name_format": "name format of the attribute to be added to the response",
|
||||||
|
"value": "value of the attribute to be added to the response"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sent information Event
|
||||||
|
|
||||||
|
The information sent to the Endpoint is structured as JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"aggregateID": "ID of the aggregate",
|
||||||
|
"aggregateType": "Type of the aggregate",
|
||||||
|
"resourceOwner": "Resourceowner the aggregate belongs to",
|
||||||
|
"instanceID": "ID of the instance the aggregate belongs to",
|
||||||
|
"version": "Version of the aggregate",
|
||||||
|
"sequence": "Sequence of the event",
|
||||||
|
"event_type": "Type of the event",
|
||||||
|
"created_at": "Time the event was created",
|
||||||
|
"userID": "ID of the creator of the event",
|
||||||
|
"event_payload": "Base64 encoded content of the event"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -71,6 +363,8 @@ To ensure the integrity of request content, each call includes a 'ZITADEL-Signat
|
|||||||
Each Target resource now contains also a Signing Key, which gets generated and returned when a Target is [created](/apis/resources/action_service_v2/action-service-create-target),
|
Each Target resource now contains also a Signing Key, which gets generated and returned when a Target is [created](/apis/resources/action_service_v2/action-service-create-target),
|
||||||
and can also be newly generated when a Target is [patched](/apis/resources/action_service_v2/action-service-patch-target).
|
and can also be newly generated when a Target is [patched](/apis/resources/action_service_v2/action-service-patch-target).
|
||||||
|
|
||||||
|
For an example on how to check the signature, [refer to the example](/guides/integrate/actions/testing-request-signature).
|
||||||
|
|
||||||
## Execution
|
## Execution
|
||||||
|
|
||||||
ZITADEL decides on specific conditions if one or more Targets have to be called.
|
ZITADEL decides on specific conditions if one or more Targets have to be called.
|
||||||
@@ -170,13 +464,6 @@ The available conditions can be found under:
|
|||||||
|
|
||||||
### Condition for Functions
|
### Condition for Functions
|
||||||
|
|
||||||
Replace the current Actions with the following flows:
|
|
||||||
|
|
||||||
- [Internal Authentication](/apis/actions/internal-authentication)
|
|
||||||
- [External Authentication](/apis/actions/external-authentication)
|
|
||||||
- [Complement Token](/apis/actions/complement-token)
|
|
||||||
- [Customize SAML Response](/apis/actions/customize-samlresponse)
|
|
||||||
|
|
||||||
The available conditions can be found under [all available Functions](/apis/resources/action_service_v2/action-service-list-execution-functions).
|
The available conditions can be found under [all available Functions](/apis/resources/action_service_v2/action-service-list-execution-functions).
|
||||||
|
|
||||||
### Condition for Events
|
### Condition for Events
|
@@ -5,7 +5,7 @@ sidebar_label: Default Settings
|
|||||||
|
|
||||||
Default settings work as default or fallback settings for your organizational settings. Most of the time you only have to set default settings for the cases where you don't need specific behavior in the organizations themselves or you only have one organization.
|
Default settings work as default or fallback settings for your organizational settings. Most of the time you only have to set default settings for the cases where you don't need specific behavior in the organizations themselves or you only have one organization.
|
||||||
|
|
||||||
To access default settings, use the settomgs page at `{instanceDomain}/ui/console/settings` or click at the default settings button on the **top-right** of the page and then navigate to settings in the navigation.
|
To access default settings, use the settings page at `{instanceDomain}/ui/console/settings` or click at the default settings button on the **top-right** of the page and then navigate to settings in the navigation.
|
||||||
|
|
||||||
<img
|
<img
|
||||||
src="/docs/img/guides/console/instancebutton.png"
|
src="/docs/img/guides/console/instancebutton.png"
|
||||||
|
@@ -471,6 +471,60 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
"guides/integrate/external-audit-log",
|
"guides/integrate/external-audit-log",
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
label: "Actions",
|
||||||
|
link: {
|
||||||
|
type: "generated-index",
|
||||||
|
title: "Use Actions to integrate ZITADEL with your Favorite Services",
|
||||||
|
slug: "/guides/integrate/actions",
|
||||||
|
description:
|
||||||
|
"With the guides in this section you will learn how to use action to integrate Zitadel with your services.",
|
||||||
|
},
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/usage",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-request",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-request-manipulation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-request-signature",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-response",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-response-manipulation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-function",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-function-manipulation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/testing-event",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "doc",
|
||||||
|
id: "guides/integrate/actions/migrate-from-v1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -782,18 +836,9 @@ module.exports = {
|
|||||||
"ZITADEL doesn't restrict the implementation languages, tooling and runtime for v2 action executions anymore.\n" +
|
"ZITADEL doesn't restrict the implementation languages, tooling and runtime for v2 action executions anymore.\n" +
|
||||||
"Instead, it calls external endpoints which are implemented and maintained by action v2 users.\n"+
|
"Instead, it calls external endpoints which are implemented and maintained by action v2 users.\n"+
|
||||||
"\n" +
|
"\n" +
|
||||||
"Please make sure to enable the `actions` feature flag on your instance to use this service and that you're running ZITADEL V3.",
|
"Please make sure to enable the `actions` feature flag on your instance to use this service and that you're running Zitadel V3.",
|
||||||
},
|
},
|
||||||
items: [
|
items: sidebar_api_actions_v2,
|
||||||
{
|
|
||||||
type: "doc",
|
|
||||||
id: "apis/actions/v2/usage",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "doc",
|
|
||||||
id: "apis/actions/v2/testing-locally",
|
|
||||||
},
|
|
||||||
].concat(sidebar_api_actions_v2),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@@ -6153,9 +6153,9 @@ ignore@^5.2.0, ignore@^5.2.4:
|
|||||||
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
|
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
|
||||||
|
|
||||||
image-size@^1.0.2:
|
image-size@^1.0.2:
|
||||||
version "1.1.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.1.1.tgz#ddd67d4dc340e52ac29ce5f546a09f4e29e840ac"
|
resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.2.1.tgz#ee118aedfe666db1a6ee12bed5821cde3740276d"
|
||||||
integrity sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==
|
integrity sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==
|
||||||
dependencies:
|
dependencies:
|
||||||
queue "6.0.2"
|
queue "6.0.2"
|
||||||
|
|
||||||
|
@@ -18,6 +18,9 @@ func AuthRequestField(authRequest *domain.AuthRequest) func(c *actions.FieldConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AuthRequestFromDomain(c *actions.FieldConfig, request *domain.AuthRequest) goja.Value {
|
func AuthRequestFromDomain(c *actions.FieldConfig, request *domain.AuthRequest) goja.Value {
|
||||||
|
if request == nil {
|
||||||
|
return c.Runtime.ToValue(nil)
|
||||||
|
}
|
||||||
var maxAuthAge *time.Duration
|
var maxAuthAge *time.Duration
|
||||||
if request.MaxAuthAge != nil {
|
if request.MaxAuthAge != nil {
|
||||||
maxAuthAgeCopy := *request.MaxAuthAge
|
maxAuthAgeCopy := *request.MaxAuthAge
|
||||||
|
@@ -633,6 +633,10 @@ func (l *Login) autoCreateExternalUser(w http.ResponseWriter, r *http.Request, a
|
|||||||
// renderExternalNotFoundOption renders a page, where the user is able to edit the IDP data,
|
// renderExternalNotFoundOption renders a page, where the user is able to edit the IDP data,
|
||||||
// create a new externalUser of link to existing on (based on the IDP template)
|
// create a new externalUser of link to existing on (based on the IDP template)
|
||||||
func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *query.DomainPolicy, human *domain.Human, idpLink *domain.UserIDPLink, err error) {
|
func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *query.DomainPolicy, human *domain.Human, idpLink *domain.UserIDPLink, err error) {
|
||||||
|
if authReq == nil {
|
||||||
|
l.renderError(w, r, nil, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
resourceOwner := determineResourceOwner(r.Context(), authReq)
|
resourceOwner := determineResourceOwner(r.Context(), authReq)
|
||||||
if orgIAMPolicy == nil {
|
if orgIAMPolicy == nil {
|
||||||
orgIAMPolicy, err = l.getOrgDomainPolicy(r, resourceOwner)
|
orgIAMPolicy, err = l.getOrgDomainPolicy(r, resourceOwner)
|
||||||
|
Reference in New Issue
Block a user