# FAPI 2.0 conformance-suite run

HelixIAM was run as a FAPI 2.0 authorization server against the FAPI 2.0 Security Profile and Message Signing test
plans of the OpenID Foundation conformance suite, with the suite playing the client. This is a **self-run** of the
OpenID Foundation conformance suite 5.3.3 (revision `f0133e9`), **not a certification**: FAPI certification is granted
by the OpenID Foundation itself and has not been requested yet. HelixIAM is **not** FAPI certified.

**Outcome (2026-11-03).** All four plans ran to the end, every module finished, with **0 failures** in 198 module
runs, all against the server build released as `v1.1.0-rc.15`. Warnings are allowed for certification; the review
modules need a person to look at a screenshot (below).

## What was run

| | |
|---|---|
| Suite | `registry.gitlab.com/openid/conformance-suite`, **version 5.3.3** (`release-v5.3.3`), revision **`f0133e9`**. Source: <https://gitlab.com/openid/conformance-suite> |
| HelixIAM | The server of `v1.1.0-rc.15` (commit `8ffa01ad`), default (production) profile, behind a TLS-terminating nginx (TLS 1.2/1.3, BCP 195 AEAD suites, HSTS) that forwards the client certificate as a certificate proxy |
| Realm | `fapi2` with the security profile **FAPI 2.0** ([FAPI 2.0 & mutual TLS](../integration/fapi2.md)); test clients with PS256 keys (`private_key_jwt`, the JWK Set by value) and client certificates from the run's own CA (the trust anchors for `tls_client_auth`), scopes `openid profile email address phone` |
| Logs | `docs/compliance/fapi2-conformance/2026-11-03/` in the product repository: the suite's JSON export of every module (gzipped, secrets, credentials and private keys removed), the screenshots uploaded for review modules, and `results.json` |

## Results

| Plan | Suite plan | Variant | Modules | Pass | Review | Warning | Fail |
|---|---|---|---:|---:|---:|---:|---:|
| P1 | `fapi2-security-profile-final-test-plan` | `private_key_jwt`, DPoP, OpenID Connect | 52 | 46 | 3 | 3 | **0** |
| P2 | `fapi2-security-profile-final-test-plan` | `private_key_jwt`, mutual TLS, OpenID Connect | 43 | 37 | 3 | 3 | **0** |
| P3 | `fapi2-security-profile-final-test-plan` | mutual TLS client authentication (`tls_client_auth`), mutual TLS, OpenID Connect | 37 | 31 | 3 | 3 | **0** |
| MS1 | `fapi2-message-signing-final-test-plan` | `private_key_jwt`, DPoP, signed request objects at PAR (JAR), JARM, OpenID Connect | 66 | 60 | 3 | 3 | **0** |
| **Total** | | | **198** | **174** | **12** | **12** | **0** |

Every plan used `fapi_profile=plain_fapi`, `authorization_request_type=simple` and `grant_management=disabled`. No
module was skipped.

### Warnings (three per plan)

- **Discovery member unknown to the suite** (`verified_claims_supported`): OpenID Connect for Identity Assurance 1.0
  metadata. RFC 8414 §2 and OpenID Connect Discovery 1.0 §3 allow additional metadata.
- **ID token claims not requested** (`realm_access`, `helix_grant`, `helix_token_type`): OpenID Connect Core 1.0 §2
  allows other claims. The same warning as W1 of the [OpenID Connect run](oidc-conformance.md).
- **Claim names unknown to the suite** in the claims-parameter test (`realm_access`, `sid`): every requested claim is
  returned; the extra claims are HelixIAM's roles and the OpenID Connect session id.

### Review modules (three per plan)

Each has a screenshot of what HelixIAM showed:

- a `request_uri` reused before its first use completed: the **sign-in page** (the suite expects it);
- a `request_uri` that was already used, and one pushed by another client: the error page **"Sign-in request no longer
  valid"** (it has expired, was already used, or was started by another application).

For the modules where the suite accepts either an error page or a completed flow (a different `nonce` or `state`
outside the pushed request, a long `nonce` or `state`, a `state` only outside the pushed request), HelixIAM completes
the flow with only the pushed parameters (RFC 9126 §4), the suite's checks pass, and the modules finish as passed.

## Not covered

- Other FAPI 2.0 variants: ecosystem profiles (`fapi_profile` other than `plain_fapi`), the OAuth-only variant,
  rich authorization requests, grant management, Message Signing with mutual TLS, signed introspection responses and
  HTTP message signatures.
- A production TLS front end (the run's nginx stands in for it) and an external review of the results.

## Reproducing the run

The harness is `e2e/oidf-conformance/` in the product repository (README, section "FAPI 2.0"): it starts the suite and
a TLS proxy in Docker, runs HelixIAM, seeds the realm (`seed.sh fapi2`) and drives the four plans headless
(`run.sh <label> fapi2`). `export.sh` writes the redacted logs and fails if a secret survives. The same harness has a
hosted mode for a run on www.certification.openid.net, the step before a certification request.
