> ## 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.

# Validate responses

> Everything your service provider must check before it trusts a FaceSign response.

FaceSign signs what it sends. Deciding whether to trust it is your service provider's job, and
so is the final access decision. This is the checklist.

<Warning>
  If your SP validates only the assertion signature, or only the response signature, it will
  accept material this pilot considers invalid. Check both.
</Warning>

## The checklist

<Steps>
  <Step title="Both signatures">
    On success the root Response **and** the nested Assertion are each signed. Verify both
    against the X.509 certificate published in the
    [live metadata](https://idp.facesign.dev/api/saml/metadata).
  </Step>

  <Step title="Status">
    `Success` means a pass. Top-level `Responder` with nested `AuthnFailed` means a refusal —
    a real, signed, deliberate "no", with no assertion attached. Never treat a refusal as a
    login.
  </Step>

  <Step title="InResponseTo">
    Must match the ID of the AuthnRequest you issued. This is what stops a response captured
    from an earlier login being replayed into a new one.
  </Step>

  <Step title="Audience">
    The `Conditions/AudienceRestriction` must name your entityID. A response minted for a
    different SP must not be accepted.
  </Step>

  <Step title="Time conditions">
    Honour `NotBefore` and `NotOnOrAfter` on both `Conditions` and
    `SubjectConfirmationData`, with whatever clock skew you allow.
  </Step>

  <Step title="Recipient and Destination">
    `Recipient` must be your ACS URL.
  </Step>

  <Step title="Single use">
    Record the assertion ID and reject duplicates. **This is your responsibility** — the
    loopback does not stand in for it, and FaceSign does not enforce it on your behalf.
  </Step>
</Steps>

## What a pass does not tell you

Re-stating it here because this is the page an integrator reads while writing the code that
grants access:

* A pass attests **a live, willing human was present**. It does not attest **who** they are.
* An echoed NameID is the value *you* supplied. It is a correlation hint, not proof.
* Keep the directory-identity binding on your own first factor.
* The access decision is yours.

## Deny, timeout, and unavailable

Design your fallback for three distinct situations, because they mean different things:

| Situation                                    | On the wire                                      | Reasonable fallback                                               |
| -------------------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------- |
| The person was refused                       | Signed `Responder` / `AuthnFailed`, no assertion | Block, and consider alerting — a refusal can indicate duress      |
| FaceSign could not produce a verdict in time | Same shape as above today                        | Fall back to another factor rather than hard-blocking a real user |
| FaceSign unreachable                         | No response at all; your own timeout fires       | Your existing IdP-unavailable path                                |

<Note>
  The first two are currently indistinguishable on the wire. A status taxonomy that separates
  "the check failed" from "we could not run the check" is not available in this release. If your policy needs to tell
  them apart, raise it before you build against the current behaviour.
</Note>

## Related

<Card title="Troubleshooting" icon="wrench" href="/troubleshooting">
  Concrete errors and what they mean.
</Card>
