FAPI 2.0 Security Profile — Versola Docs
VersolaVersola/docs
Pre-1.00.7.1versola.kzGitHub

FAPI 2.0 Security Profile

Requirement-by-requirement checklist of the FAPI 2.0 Security Profile rules that Versola enforces on tenants with the fapi2 security profile.

Specification: FAPI 2.0 Security Profile

FAPI 2.0 narrows OAuth 2.0 for high-risk APIs: confidential clients, pushed authorization requests, PKCE and sender-constrained access tokens. In Versola these rules apply to every client of a tenant whose security profile is fapi2, which is the default for new tenants.

Status

Partially implemented. Checked claims: 31 of 35.

Versola is not FAPI 2.0 certified yet, and no conformance certification is claimed. We plan to go through the certification. Versola has not been through the OpenID Foundation FAPI 2.0 conformance suite, and no conformance-suite results are published. Each line below is backed by code and by an end-to-end test in the product repository; the test names are given in parentheses.

Client registration

central checks these when a client is created or patched and lists every violation in one error.

  • Confidential clients only — a public client (authMethod: none) is refused at registration, and a public client that already exists is refused with invalid_client at /token, /par, /introspect and /revoke (§5.3.2.1; SecurityProfileApiSpec, SecurityProfileRuntimeSpec)
  • Client authentication by private_key_jwt, tls_client_auth or self_signed_tls_client_auth only — a client_secret client is refused (§5.3.2.1; SecurityProfileApiSpec)
  • Sender-constrained access tokens required — the client sets dpopBoundAccessTokens, authenticates with a certificate, or sets certificateBoundAccessTokens (§5.3.2.2; SecurityProfileApiSpec)
  • Pushed authorization requests required for every client that has a redirect URI — requirePushedAuthorizationRequests (§5.3.2.2; SecurityProfileApiSpec)
  • https redirect URIs only; loopback http is allowed for native clients, and for any client outside prod; private-use schemes are refused (§5.3.2.2; SecurityProfileApiSpec)
  • A patch that would take a client out of the profile is refused (SecurityProfileApiSpec)
  • The profile is fixed when the tenant is created and cannot be switched later (SecurityProfileApiSpec)

Authorization request

  • Only the authorization code flow is offered for plain OAuth — implicit and resource owner password grants are not implemented
  • Pushed authorization requests — POST /par returns a single-use request_uri bound to the pushing client (see RFC 9126; PushedAuthorizationSpec)
  • PKCE with S256 required for every client, including confidential ones; plain is not accepted (see RFC 7636; PushedAuthorizationSpec)
  • Redirect URIs matched by exact string comparison
  • The authorization response carries iss (see RFC 9207)
  • Signed request objects (JAR) are accepted: nbf required and at most 60 minutes old, exp at most 60 minutes after nbf, jti required and replay-checked, aud exactly the issuer string (see RFC 9101; JarFlowSpec)
  • JARM signed authorization responses are available as an option (see JARM; JarmFlowSpec)
  • response_type=code id_token refused for fapi2 clients — not enforced; the hybrid flow stays available on a fapi2 tenant (with nonce required)

Client authentication

  • private_key_jwt: aud must be exactly the issuer, sent as a single string; an array or an endpoint URL is refused (§5.3.2.1-8; PrivateKeyJwtSpec)
  • iat and nbf up to 60 s in the future are accepted, further ahead is refused (§5.3.2.1-13; PrivateKeyJwtSpec)
  • Assertion lifetime bounded by the tenant’s client-assertion maximum (30–900 s, default 300 s), and every jti is single use (PrivateKeyJwtSpec)
  • A client that registered keys cannot authenticate with a secret, and two methods in one request are refused (PrivateKeyJwtSpec)
  • tls_client_auth and self_signed_tls_client_auth at /token, /par, /introspect and /revoke, through the mutual TLS listener or a proxy-forwarded certificate (see RFC 8705; MutualTlsListenerSpec, MutualTlsSpec)

Token endpoint

  • Authorization codes are single use; presenting a used code revokes the tokens issued from it
  • Cache-Control: no-store and Pragma: no-cache on token responses
  • Refresh tokens are bound to the sender key or certificate of the grant (see RFC 9449 and RFC 8705; MutualTlsSpec)

Sender-constrained tokens

  • DPoP proofs validated for typ, embedded jwk, htm, htu, iat, jti and ath, with cnf.jkt in the token (see RFC 9449)
  • DPoP replay protection shared across replicas
  • DPoP key policy: RSA keys under 2048 bits are refused and a client can narrow the accepted algorithms (DpopKeyPolicySpec)
  • Server-provided DPoP nonce — use_dpop_nonce and DPoP-Nonce, enabled per tenant with requireDpopNonce (off by default)
  • Certificate-bound tokens: cnf.x5t#S256 in the token and in introspection, enforced at /userinfo (see RFC 8705; MutualTlsSpec)
  • A key-bound token presented as Bearer is refused at /userinfo and at edge (DpopBoundTokenSpec)

Algorithms

  • A fapi2 tenant cannot select an RS256 signing key; PS256 and ES256 keys are accepted (SigningKeySelectionSpec)
  • DPoP proofs, client assertions and request objects default to ES256 and PS256; RS256 is not in the default set
  • RS256 excluded from DPoP, client-assertion and request-object algorithm lists for fapi2 tenants — not enforced per tenant; these lists are deployment-wide metadata, and an operator who adds RS256 to them admits it for every tenant
  • EdDSA — not supported

Resource server

  • edge verifies the DPoP proof, ath, the key binding and replay on every proxied call, and refuses a token bound to both key and certificate on every presentation (see Edge; DpopBoundTokenSpec)

Transport

  • TLS version and cipher-suite restrictions — not enforced by Versola; TLS terminates at the reverse proxy or ingress that the operator configures

Notes

  • The standard profile is not FAPI-shaped. It admits client secrets, public clients, RS256 signing keys and, for confidential clients, requests without PKCE.
  • Apps fronted by edge keep the FAPI shape on either profile: certificate-bound tokens for web clients, DPoP-bound tokens and App Link redirects for native ones.
  • The FAPI 2.0 Message Signing parts (JAR, JARM) are optional features here and are not forced by the profile.

Where to look

Security profiles explains the fapi2 and standard profiles, and Sender-constrained tokens explains DPoP and certificate binding.