
# Download the SAML SP metadata of a connection

`GET /v1/connections/{connection_id}/sp-metadata` · permission `connections:read`

Downloads the signed SAML 2.0 service provider (SP) metadata document of an enterprise SAML connection: the file the identity provider's administrator uploads to the identity provider. It is the same document the connection's public metadata address (`https://<sp host>/saml/<conn_…>/metadata`) serves:

- `entityID`, `validUntil` (7 days ahead) and `cacheDuration` (`PT24H`);
- the signing and encryption certificates (two of each during a yearly key rotation window);
- the supported NameID formats, the assertion consumer service (HTTP-POST) and the single logout endpoints;
- an enveloped XML signature made with the connection's active SP signing key.

The SP keys are created on first use if they do not exist yet. The document contains no secret. Reads are not audited.

With `revision_id` you get the document of a [draft revision](revisions.md) instead. For an [SP host migration](migrate-sp-host.md) it carries the endpoints on the new host: give it to the identity provider's administrator before you publish the revision.

## Request

| Field | Type | Required | Description |
|---|---|---|---|
| `connection_id` | path | yes | Enterprise connection ID (`conn_…`). |
| `revision_id` | query | no | A draft revision of the connection (`connrev_…`). |

## Response

`200 OK` with the XML document as the body:

| Header | Value |
|---|---|
| `Content-Type` | `application/samlmetadata+xml` |
| `Content-Disposition` | `attachment; filename="<conn_…>-sp-metadata.xml"` |
| `Cache-Control` | `no-store` |

```xml
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    ID="_…" entityID="https://acme.eu.keenauth.app/saml/conn_01j9xp6q0r1s5t7v9w1x3y5z7b/metadata"
    validUntil="2026-11-02T10:00:00Z" cacheDuration="PT24H">
  <ds:Signature>…</ds:Signature>
  <md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    …
  </md:SPSSODescriptor>
</md:EntityDescriptor>
```

## Errors

| HTTP | code | When |
|---|---|---|
| 404 | `not_found` | The connection does not exist in this environment or is not an enterprise connection. |
| 409 | `conflict` | The connection is not a SAML connection, or has no SAML configuration yet. |
| 422 | `validation_failed` | `revision_id` is malformed or repeated (`invalid_value`, `repeated`), or not a draft revision of this connection (`not_found`); `errors[]` points at `/revision_id`. |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks the required permission. |
| 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 -o sp-metadata.xml "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b/sp-metadata" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
```

```bash
keenauth connections sp-metadata conn_01j9xp6q0r1s5t7v9w1x3y5z7b --file sp-metadata.xml
```

Without `--file` the CLI writes the XML to standard output. An existing file is never overwritten.
