diff --git a/en/asgardeo/docs/apis/restapis/flow-extension-management.yaml b/en/asgardeo/docs/apis/restapis/flow-extension-management.yaml index 985b188531..9bbcee5c64 100644 --- a/en/asgardeo/docs/apis/restapis/flow-extension-management.yaml +++ b/en/asgardeo/docs/apis/restapis/flow-extension-management.yaml @@ -583,6 +583,7 @@ components: $ref: '#/components/schemas/ContextPath' modify: type: array + description: The paths the extension may write. Paths configured as non-modifiable are rejected with a 400 response. items: $ref: '#/components/schemas/ContextPath' diff --git a/en/asgardeo/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml b/en/asgardeo/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml index 3c91653d40..a72135748f 100644 --- a/en/asgardeo/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml +++ b/en/asgardeo/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml @@ -203,6 +203,10 @@ components: flowType: type: string description: The flow being executed. + enum: + - REGISTRATION + - PASSWORD_RECOVERY + - INVITED_USER_REGISTRATION example: REGISTRATION flowId: type: string diff --git a/en/identity-server/next/docs/_data/configuration_catalog.yaml b/en/identity-server/next/docs/_data/configuration_catalog.yaml index 63c4e38e90..c446b15cfc 100644 --- a/en/identity-server/next/docs/_data/configuration_catalog.yaml +++ b/en/identity-server/next/docs/_data/configuration_catalog.yaml @@ -2761,6 +2761,22 @@ sections: description: > The number of times the HTTP client retries a failed request to an action endpoint. + - id: actions.types.flow_extension + hyperlink: flow-extension-action + title: Flow extension action + tasks: [configure-actions] + description: > + Settings for the flow extension action type, which calls an external service from within a flow. + + configs: + - key: non_modifiable_paths + type: array + required: false + default: '["/user/claims[uri=http://wso2.org/claims/userid]", "/user/claims[uri=http://wso2.org/claims/created]"]' + description: > + The flow context paths that a flow extension can never write, given as a list of context paths. + Attributes take the form /user/claims[uri=<claim URI>]. + # ─────────────────────────── IDENTITY MANAGEMENT ─────────────────────────── - id: identity_mgt.user_self_registration diff --git a/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-certificate.mp4 b/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-certificate.mp4 new file mode 100644 index 0000000000..b72eba3587 Binary files /dev/null and b/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-certificate.mp4 differ diff --git a/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-settings.png b/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-settings.png new file mode 100644 index 0000000000..661316fdb4 Binary files /dev/null and b/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-settings.png differ diff --git a/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-toggles.png b/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-toggles.png new file mode 100644 index 0000000000..c9579c2c78 Binary files /dev/null and b/en/identity-server/next/docs/assets/img/guides/flows/flow-extension-encryption-toggles.png differ diff --git a/en/identity-server/next/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml b/en/identity-server/next/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml index 93ee49bfb5..82ce173f09 100644 --- a/en/identity-server/next/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml +++ b/en/identity-server/next/docs/references/service-extensions/in-flow-extensions/flow-extension/api/flow-extension-action-v1.yaml @@ -203,6 +203,10 @@ components: flowType: type: string description: The flow being executed. + enum: + - REGISTRATION + - PASSWORD_RECOVERY + - INVITED_USER_REGISTRATION example: REGISTRATION flowId: type: string diff --git a/en/includes/guides/flows/flow-extension-configuration.md b/en/includes/guides/flows/flow-extension-configuration.md index 4dbea427f1..a4d78f454a 100644 --- a/en/includes/guides/flows/flow-extension-configuration.md +++ b/en/includes/guides/flows/flow-extension-configuration.md @@ -78,7 +78,25 @@ Once the extension and its attributes exist, configure which attributes {{produc ![Configure a flow extension]({{base_path}}/assets/img/guides/flows/flow-extension-configure.gif){: width="auto" style="display: block; margin: 0;"} -The flow extension is now ready to be invoked from the **Self Registration** flow. +The flow extension is now ready to be added to a flow. + +#### Attribute access levels + +Most attributes accept both **Read** and **Write**. The following are the exceptions: + +| Attribute | Available access | Notes | +| --------- | ---------------- | ----- | +| Attributes marked with a **Read-Only** badge | Read | {{product_name}} owns these values, so their **Write** control is disabled. | +| Username | Read and Write | Applied in the **Self Registration** flow only. In **Password Recovery** and **Invited User Registration**, {{product_name}} omits the username from the request and ignores any change your endpoint returns. | +| Identity attributes | Read and Write | {{product_name}} maintains these itself, so writing one can cause unexpected behavior. | + +{% if product_name == "WSO2 Identity Server" %} + +!!! note + + The read-only attributes are set by the `actions.types.flow_extension.non_modifiable_paths` property. See [Flow extension action]({{base_path}}/references/configuration-catalog/#flow-extension-action) in the configuration catalog. + +{% endif %} ### Step 4 – Configure field encryption @@ -102,7 +120,6 @@ To mark a field as encrypted: Fields marked as encrypted show a lock icon on their **Read** and **Write** indicators. - ![Configure field encryption]({{base_path}}/assets/img/guides/flows/flow-extension-encryption-toggles.png){: width="auto" style="display: block; margin: 0; border: 0.3px solid lightgrey;"} !!! note diff --git a/en/includes/guides/flows/flow-extension-external-service.md b/en/includes/guides/flows/flow-extension-external-service.md index b5049e17a4..356c3a7f8d 100644 --- a/en/includes/guides/flows/flow-extension-external-service.md +++ b/en/includes/guides/flows/flow-extension-external-service.md @@ -2,6 +2,8 @@ A flow extension calls an external HTTP service that you build and host. This service is where your custom logic runs. Use it to enrich user claims during registration, validate input against an external system, derive computed claims, or stop a flow with a business-rule failure. +One service can be used in more than one flow. {{product_name}} sends the flow type on every request, so you can write your endpoint to branch on it. + This guide explains the contract your service must implement so that {{product_name}} can integrate with it. You can build the service in any language or framework you prefer. ## How it works @@ -345,7 +347,8 @@ Use `ERROR` when your service itself hits a processing or server error (a downst **Problems that skip the operation.** The following cause {{product_name}} to skip the offending operation and apply the rest, so a single invalid operation doesn't fail the user's flow: - The path is empty, unknown, or read-only (everything under `/flow/`). -- The claim URI isn't in the `http://wso2.org/claims/` dialect, refers to an identity claim (`http://wso2.org/claims/identity/*`), or doesn't resolve to an attribute registered in your organization. +- The path is one the extension may not write, either because {{product_name}} owns the attribute or because the current flow withholds it. See [attribute access levels]({{base_path}}/guides/flows/flow-extension-configuration/#attribute-access-levels). +- The claim URI isn't in the `http://wso2.org/claims/` dialect, or doesn't resolve to an attribute registered in your organization. - The value is `null` or has the wrong type, for example, a plain string for a multi-valued claim, or an array for a single-valued claim. !!! note diff --git a/en/includes/guides/flows/flow-extensions/index.md b/en/includes/guides/flows/flow-extensions/index.md index d969c7ca9d..f8aa38b6e4 100644 --- a/en/includes/guides/flows/flow-extensions/index.md +++ b/en/includes/guides/flows/flow-extensions/index.md @@ -2,9 +2,17 @@ A **flow extension** lets you call your own external service from within a flow. This allows you to inject custom business logic, such as validation, enrichment, or risk evaluation, into a user journey without building it into the flow itself. -!!! note +## Supported flows - Flow extensions are currently supported only in the **Self Registration** flow. +You can add a flow extension to any of the following flows. + +| Flow | Flow type in the request | +| ---- | ------------------------ | +| [Self Registration]({{base_path}}/guides/flows/self-registration/) | `REGISTRATION` | +| [Password Recovery]({{base_path}}/guides/flows/password-recovery/) | `PASSWORD_RECOVERY` | +| [Invited User Registration]({{base_path}}/guides/flows/invited-user-registration/) | `INVITED_USER_REGISTRATION` | + +You can reuse one extension across more than one flow. Every request tells your endpoint which flow invoked it, so a single service can branch on the flow type instead of you registering a separate extension per flow. ## How it works @@ -17,6 +25,17 @@ A flow extension follows a simple request-response cycle: Because the logic runs entirely in your own service, you control the data sources and business rules without embedding them into the flow itself. +## What an extension can read and write + +An extension only ever sees and changes what you allow. You declare this per attribute in the extension's access configuration, using two independent access levels. + +- **Read:** Retrieves the attribute's current value and includes it in the request that {{product_name}} sends to your endpoint. +- **Write:** Allows your endpoint to return a value for that attribute, which {{product_name}} then applies to the flow. + +{{product_name}} enforces these declarations on both legs of the call. The request carries only the attributes you marked as **Read**, and an `allowedOperations` whitelist that names exactly the attributes you marked as **Write**. Anything your endpoint returns outside that whitelist is discarded. + +Two things narrow this further. {{product_name}} owns a small number of attributes that no extension may write, and a few attributes are available only in some flows. So an extension reused across flows can legitimately receive a smaller payload in one flow than in another. For the full picture, see [attribute access levels]({{base_path}}/guides/flows/flow-extension-configuration/#attribute-access-levels). + You can also encrypt individual field values exchanged with your endpoint, so sensitive data such as credentials never travels in plain text. To learn more, see [configure field encryption]({{base_path}}/guides/flows/flow-extension-configuration/#step-4-configure-field-encryption). ## What's next