> ## Documentation Index
> Fetch the complete documentation index at: https://idp-docs.facesign.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Response contract

> Signed success and denial responses that Silverfort Bridge must validate.

## Success response

A successful response contains one Assertion. FaceSign signs the root Response and the nested
Assertion separately. This sample is abridged and uses synthetic values:

```xml theme={null}
<samlp:Response
  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
  xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
  ID="_response-001"
  Version="2.0"
  IssueInstant="2026-08-11T12:00:00Z"
  Destination="https://bridge-sandbox.example.invalid/saml/acs"
  InResponseTo="_request-001">
  <saml:Issuer>https://idp.facesign.dev/api/saml/metadata</saml:Issuer>
  <ds:Signature>...root Response signature...</ds:Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
  </samlp:Status>
  <saml:Assertion ID="_assertion-001" Version="2.0" IssueInstant="2026-08-11T12:00:00Z">
    <saml:Issuer>https://idp.facesign.dev/api/saml/metadata</saml:Issuer>
    <ds:Signature>...nested Assertion signature...</ds:Signature>
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
        facesign-session:session_example_001
      </saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData
          Recipient="https://bridge-sandbox.example.invalid/saml/acs"
          InResponseTo="_request-001"
          NotOnOrAfter="2026-08-11T12:05:00Z" />
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2026-08-11T12:00:00Z" NotOnOrAfter="2026-08-11T12:05:00Z">
      <saml:AudienceRestriction>
        <saml:Audience>https://bridge-sandbox.example.invalid/saml/metadata</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2026-08-11T12:00:00Z" SessionIndex="_session-001">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>
          urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
        </saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="facesign.verdict"><saml:AttributeValue>verified_human</saml:AttributeValue></saml:Attribute>
      <saml:Attribute Name="facesign.sessionId"><saml:AttributeValue>session_example_001</saml:AttributeValue></saml:Attribute>
      <saml:Attribute Name="facesign.coercionScore"><saml:AttributeValue>0.05</saml:AttributeValue></saml:Attribute>
      <saml:Attribute Name="facesign.deepfakeResistanceScore"><saml:AttributeValue>0.92</saml:AttributeValue></saml:Attribute>
      <saml:Attribute Name="facesign.repudiationArtifactPresent"><saml:AttributeValue>false</saml:AttributeValue></saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>
```

## Released attributes

| Attribute                             | Current success value      | How to use it                                                                                             |
| ------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------- |
| `facesign.verdict`                    | `verified_human`           | The only verdict currently released in a success assertion. A non-pass has no assertion.                  |
| `facesign.sessionId`                  | String                     | Correlation identifier for support and audit.                                                             |
| `facesign.coercionScore`              | Decimal string from 0 to 1 | Bounded launch-profile output. It is not a calibrated probability or an independent authorization signal. |
| `facesign.deepfakeResistanceScore`    | Decimal string from 0 to 1 | Bounded launch-profile output with the same caveat.                                                       |
| `facesign.repudiationArtifactPresent` | Literal string `"false"`   | Reserved. Do not branch on it.                                                                            |

## NameID behavior

By default, success uses a transient `facesign-session:<sessionId>` NameID. An approved isolated
sandbox may echo the Subject NameID supplied by Bridge. That echo is correlation data from the
unsigned request, not FaceSign proof of the workforce identity.

## Denial response

A completed non-pass or analysis failure may return a signed denial. It has no Assertion,
NameID, or attributes. Only the root Response is signed.

```xml theme={null}
<samlp:Response
  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
  xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
  ID="_response-deny-001"
  Version="2.0"
  IssueInstant="2026-08-11T12:00:00Z"
  Destination="https://bridge-sandbox.example.invalid/saml/acs"
  InResponseTo="_request-002">
  <saml:Issuer>https://idp.facesign.dev/api/saml/metadata</saml:Issuer>
  <ds:Signature>...root Response signature...</ds:Signature>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed" />
    </samlp:StatusCode>
    <samlp:StatusMessage>Verification did not pass</samlp:StatusMessage>
  </samlp:Status>
</samlp:Response>
```

## Signature profile

The deployed build emits RSA-SHA256 signatures, SHA-256 digests, and exclusive XML
canonicalization. On success, it signs the root Response and nested Assertion separately. On
denial, it signs only the root Response; there is no Assertion.

Trust the current X.509 certificate from the [live metadata](https://idp.facesign.dev/api/saml/metadata).
Do not pin a certificate copied from an example or sample response. Incoming AuthnRequests remain
unsigned; if Bridge requires signing, record that incompatibility before UAT.

<h2 id="validation-checklist">Validation checklist</h2>

<Steps>
  <Step title="Read Status first">
    Continue only when the top-level status is `Success`. Reject any non-success as a login and
    reject a non-success response that contains an Assertion.
  </Step>

  <Step title="Validate the required signatures">
    On success, validate the root Response signature and the nested Assertion signature against
    the certificate in FaceSign metadata. On denial, validate the root Response signature.
  </Step>

  <Step title="Correlate the request">
    Match `InResponseTo` on the Response and bearer confirmation data to an outstanding request.
  </Step>

  <Step title="Check where and when it applies">
    Validate `Destination`, `Recipient`, `Audience`, `NotBefore`, and both `NotOnOrAfter` values.
    Apply Silverfort's documented clock-skew policy.
  </Step>

  <Step title="Reject duplicates durably">
    Store accepted Response and Assertion IDs in a durable duplicate store and reject reuse.
  </Step>

  <Step title="Validate RelayState separately">
    Use RelayState only to resume application state. It is not identity or authentication evidence.
  </Step>
</Steps>

## Replay responsibilities

`InResponseTo` provides correlation, but it does not by itself prevent replay. The deployed IdP
does not reject a repeated AuthnRequest ID on Silverfort's behalf. Silverfort must durably reject
duplicate Response and Assertion IDs and consume each outstanding request once.

## Fallback semantics

A signed `Responder/AuthnFailed` is an authenticated non-success. A pre-flow HTTP error and an
unreachable or late flow may produce no usable SAML response. Silverfort owns the fallback for
each case. None may be converted to `Success` or treated as a valid step-up.
