
# Set IdP-initiated sign-in for a SAML connection

`PUT /v1/connections/{connection_id}/idp-initiated` · permission `connections:write`

Allows or turns off IdP-initiated sign-in (an unsolicited SAML response sent from the identity provider's app portal) for an enterprise SAML connection, and sets the applications the user may land in. It is off by default.

- **Full replace:** every request writes all three fields. An omitted `idp_initiated_default_application_id` and an empty `idp_initiated_allowed_application_ids` are cleared.
- **Targets:** each application must exist in this environment, sign users in through a browser (not machine-to-machine, management or a client ID metadata document client) and have an `initiate_login_uri`. After sign-in the browser is sent to that address with `iss`, and the application starts its own authorization request with `state` and PKCE.
- **RelayState:** when the identity provider sends a RelayState, it selects an application only if it equals that application's `client_id` byte for byte and the application is the default or in the allowed list. RelayState is never treated as a URL.
- **Security:** this setting accepts responses your users did not start, so a dashboard user needs a fresh step-up authentication and the `owner` or `admin` role. The Admin Portal cannot change it.

## Request

| Field | Type | Required | Description |
|---|---|---|---|
| `connection_id` | path | yes | Enterprise SAML connection ID (`conn_…`). |
| `If-Match` | header | no | The connection `ETag`. A stale value fails with `412`. |
| `allow_idp_initiated` | boolean | yes | Accept unsolicited SAML responses. `true` requires `idp_initiated_default_application_id`. |
| `idp_initiated_default_application_id` | string \| null | when enabled | Application (`app_…`) used when the RelayState is empty. |
| `idp_initiated_allowed_application_ids` | array | no | Applications (`app_…`) a RelayState may select; unique, at most 20. |

## Response

`200 OK` with the connection (see [Get a connection](../connections/get.md)) and its new `ETag`. The connection shows the stored values in `allow_idp_initiated`, `idp_initiated_default_application_id` and `idp_initiated_allowed_application_ids`.

## Errors

| HTTP | code | When |
|---|---|---|
| 404 | `not_found` | The connection does not exist in this environment. |
| 412 | `precondition_failed` | `If-Match` does not match the current version. |
| 422 | `validation_failed` | The connection is not an enterprise SAML connection, the default application is missing while enabled, or an application does not meet the target rules; `errors[]` points at the field. |
| 400 | `unknown_field` | The body has an unknown field. |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks the required permission. |
| 403 | `step_up_required` | A dashboard user has not completed a recent step-up authentication. |
| 429 | `rate_limited` | The rate limit was exceeded; retry after the `Retry-After` period. |
| 503 | `service_unavailable` | A dependency is temporarily unavailable; retry after the `Retry-After` period. |

## Example

```bash
curl -X PUT "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b/idp-initiated" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"allow_idp_initiated":true,"idp_initiated_default_application_id":"app_01j9xp6q0r1s5t7v9w1x3y5z7c","idp_initiated_allowed_application_ids":["app_01j9xp6q0r1s5t7v9w1x3y5z7c"]}'
```

```bash
keenauth connections idp-initiated put conn_01j9xp6q0r1s5t7v9w1x3y5z7b --data '{"allow_idp_initiated":false}'
```
