Skip to content

OFCS conformance status

go-oidc-provider is regressed against the OpenID Foundation Conformance Suite (OFCS). The harness lives in conformance/ in the source repo and runs three plans end-to-end against a cmd/op-demo instance.

Personal project, not certified

This is a personal project maintained by an individual developer. No OpenID Foundation membership fee is paid and no formal OIDC certification is held. The numbers on this page are reproducible snapshots — make conformance-baseline records exactly what you see. They are not a substitute for a paid OpenID Foundation certification and should not be cited as one.

What gets exercised

PlanWhat it coversProfile
oidcc-basic-certification-test-planAuthorization Code + PKCE, ID Token, UserInfo, refresh, discoveryOIDC Core 1.0
fapi2-security-profile-id2-test-plan+ PAR, sender-constrained access tokens (DPoP), strict alg list, redirect_uri exact matchFAPI 2.0 Baseline
fapi2-message-signing-id1-test-plan+ JAR (signed authorization request), JARM (signed authorization response)FAPI 2.0 Message Signing

Latest baseline

Snapshot ID: 2026-04-30T11-50-08Z-post-error-html
Repository SHA: ab23d3c

PlanPASSEDREVIEWSKIPPEDFAILEDTotal
oidcc-basic-certification-test-plan3032035
fapi2-security-profile-id2-test-plan4891058
fapi2-message-signing-id1-test-plan6092071
Total1382150164

REVIEW vs FAILED — the distinction

OFCS has four terminal states: PASSED, FAILED, REVIEW, SKIPPED. REVIEW does not mean a test failed. It means the test wants a human operator to confirm something the automation cannot — for example, "did the OP show a login screen here?" The test runs, takes screenshots, then sits in a WAITING state until someone in the OFCS UI clicks "reviewed". Our headless runner records REVIEW when the test reached that state without erroring.

Why we don't auto-pass REVIEW modules

The conformance suite gates these modules on human judgment by design. A cmd/op-demo running headless can't honestly upload a screenshot of "this is what my user saw"; turning the gate off would lie about what was actually checked. The harness records REVIEW as-is, on the understanding that paid certification would require sitting in front of the UI to clear them.

Modules currently in REVIEW

oidcc-basic plan (3)

ModuleWhat it gates
oidcc-ensure-registered-redirect-uriManual confirmation that the OP refused an unregistered redirect_uri
oidcc-max-age-1Manual confirmation that max_age=1 re-prompted the user
oidcc-prompt-loginManual confirmation that prompt=login re-prompted

FAPI 2.0 plans (9 each, same set)

These all gate on a screenshot upload of the OP's error page or a manual "is the user actually re-prompted" judgment. They run cleanly headless but stay REVIEW until human sign-off:

  • fapi2-…-ensure-different-nonce-inside-and-outside-request-object
  • fapi2-…-ensure-different-state-inside-and-outside-request-object
  • fapi2-…-ensure-request-object-with-long-nonce
  • fapi2-…-ensure-request-object-with-long-state
  • fapi2-…-ensure-unsigned-authorization-request-without-using-par-fails
  • fapi2-…-par-attempt-reuse-request_uri
  • fapi2-…-par-attempt-to-use-expired-request_uri
  • fapi2-…-par-attempt-to-use-request_uri-for-different-client
  • fapi2-…-state-only-outside-request-object-not-used

The OP returns the right HTTP error in every case (the negative tests pass their internal assertions); OFCS just wants a human to inspect the rendered error UI.

Modules currently SKIPPED — and why

ModuleReason
fapi2-…-ensure-signed-client-assertion-with-RS256-failsThe FAPI client used in the plan registers token_endpoint_auth_signing_alg=PS256, so OFCS skips the per-client RS256 negative test.
fapi2-message-signing-…-ensure-signed-request-object-with-RS256-failsSame — the FAPI client's request_object_signing_alg=PS256 makes the RS256 negative test inapplicable.
oidcc-ensure-request-object-with-redirect-uriThe oidcc-basic plan does not enable JAR; the OP omits request_object_signing_alg_values_supported from discovery and OFCS skips.
oidcc-unsigned-request-object-supported-correctly-or-rejected-as-unsupportedSame — JAR off, no request parameter, OFCS skips.

"SKIPPED" is intentional, not "didn't run"

OFCS's skip decision is a function of what discovery and per-client metadata advertise. The FAPI clients in the plan declare PS256 as their token-endpoint-auth and request-object signing alg, so OFCS's "RS256 should fail" probes are not applicable and the suite marks them skipped rather than running them and recording a pass.

Reproducing the baseline yourself

sh
git clone https://github.com/libraz/go-oidc-provider.git
cd go-oidc-provider
make conformance-up
make conformance-baseline LABEL=local-check
ls conformance/baselines/   # JSON snapshot lands here

The harness:

  1. Generates self-signed RSA-2048 certs (scripts/conformance.sh certs).
  2. Brings up the OFCS Docker stack at https://localhost:8443.
  3. Builds and runs cmd/op-demo at https://127.0.0.1:9443.
  4. Seeds the three plans via the OFCS REST API.
  5. Records pass/fail per module to a deterministic JSON file.

make conformance-baseline-diff exits non-zero on any module that lost PASSED between two snapshots — that is the regression gate the project uses pre-merge for security-relevant changes.

What FAPI 2.0 means in this codebase

op.WithProfile(profile.FAPI2Baseline) activates the configuration the two fapi2-* plans are built around:

  • feature.PAR (auto-enabled by FAPI2Baseline) — /par becomes routable; request_uri accepted at /authorize
  • feature.JAR (auto-enabled by FAPI2Baseline) — request / request_uri validated as signed JWTs
  • feature.JARM (additionally auto-enabled by FAPI2MessageSigning) — authorization responses signed as JWTs
  • Sender-constrained access tokens — the embedder explicitly enables one of feature.DPoP (cnf.jkt) or feature.MTLS (cnf.x5t#S256) via WithFeature; op.New rejects the configuration if neither is enabled. Discovery advertises dpop_signing_alg_values_supported: ES256, EdDSA, PS256 when DPoP is enabled.
  • JOSE alg allow-list locked to RS256 / PS256 / ES256 / EdDSA codebase-wide; HS* and none are structurally unreachable (see internal/jose/alg.go)
  • token_endpoint_auth_methods_supported intersected with FAPI's allow-list (private_key_jwt, tls_client_auth, self_signed_tls_client_auth)
  • redirect_uri exact-string match enforced
  • per-client RequestObjectSigningAlg / TokenEndpointAuthSigningAlg narrowing pins each FAPI client to PS256 (or ES256 / EdDSA); the discovery doc still advertises the codebase-wide list

If you set conflicting options after WithProfile, op.New(...) returns a build-time error rather than letting a partial-FAPI configuration escape into production.

Where the harness lives

PathWhat it is
conformance/README.mdOperator runbook
conformance/plans/*.jsonPlan templates (server / client / resource blocks)
conformance/docker-compose.ymlOFCS image pin (release-v5.1.9) + JKS truststore wiring
scripts/conformance.shcerts / ofcs-up / op-up / seed-plans / drive / batch
tools/conformance/ofcs.pyREST client + headless drive script
conformance/baselines/*.jsonCaptured snapshots (gitignored — environment-specific)

Caveats worth naming

  • Plan suite version. OFCS is pinned to release-v5.1.9. Tests added or renamed in newer OFCS releases are not covered until the pin is bumped.
  • Headless drive. The drive script reverse-engineers the OFCS REST surface; OFCS does not document it. Behaviour confirmed against v5.1.9 only.
  • No real RP cert. The mTLS plan slots use generated self-signed certs at conformance/certs/ so the plan can be instantiated. No real CA chain is exercised.
  • Single OP instance. Cross-instance behaviour (e.g. token introspection across two OPs sharing a store) is exercised by test/scenarios, not OFCS.

The conformance harness sits next to an in-process Spec Scenario Suite under test/scenarios/. The two suites cover different layers — OFCS runs end-to-end against a live OP via HTTP, the scenario suite drives the same protocol invariants in-process — and both are required green before security-relevant changes merge.