From 01093b08234cc61e72f758a0267530f3cc1a7d9f Mon Sep 17 00:00:00 2001 From: Chris Wood Date: Fri, 18 Sep 2026 17:36:46 +0100 Subject: [PATCH] feat: Readiness for informal feedback --- proposals/2026-09-18-Security-Profiles.md | 517 ++++++++++++++++++ ..._security_profile_normative_references.svg | 60 ++ 2 files changed, 577 insertions(+) create mode 100644 proposals/2026-09-18-Security-Profiles.md create mode 100644 proposals/fapi2_security_profile_normative_references.svg diff --git a/proposals/2026-09-18-Security-Profiles.md b/proposals/2026-09-18-Security-Profiles.md new file mode 100644 index 0000000000..e33b27a14b --- /dev/null +++ b/proposals/2026-09-18-Security-Profiles.md @@ -0,0 +1,517 @@ +# Creating Decoupled Security Profiles in OpenAPI to Support FAPI 2.0 and GNAP + +## Metadata + +| Tag | Value | +| --- | --- | +| Proposal | [2026-09-18-Security-Profiles](https://github.com/OAI/OpenAPI-Specification/tree/main/proposals/2026-09-18-Security-Profiles.md) | +| Authors | [Chris Wood](https://github.com/sensiblewood) | +| Review Manager | TBD | +| Status | Proposal | +| Implementations | [Click Here](https://github.com/OAI/OpenAPI-Specification/tree/main/proposals/{YYYY-MM-DD-Short-Name}/implementations.md) | +| Issues | [{issueid}](https://github.com/OAI/OpenAPI-Specification/issues/{IssueId}) | +| Previous Revisions | [{revid}](https://github.com/OAI/OpenAPI-Specification/pull/{revid}) | + +## Change Log + +| Date | Responsible Party | Description | +| --- | --- | --- | +| 2026-09-19 | Chris Wood | Pre-PR version, "sounding board" for feedback | + +## Introduction + +A direct excerpt from the GitHub Discussion that preceded this proposal: [#5304](https://github.com/OAI/sig-security/discussions/50). + +> This proposal [therefore] suggests a way forward on unlocking the means to describe security profiles in a suitably deterministic and loosely coupled way that provides API consumers with the affordances required to accurately understand the security requirements for a given Operation. + +To add to this: The proposal also provide an approach to provide affordances for agentic use cases that enable AI agents to read and assemble OpenAPI-based tooling in a deterministic way. + +## Motivation + +This excerpt is again from the GitHub Discussion referenced [above](#introduction). + +> The OpenAPI Specification provides a number of Security Scheme objects that are, largely speaking a "point in time" view of a security requirement. +> +> Take OAuth Flow Objects for example. OAuth Flow objects create a description of the security requirements for invoking given Operation that requires providing static properties that may not duplicate properties from the source of truth for the OAuth implementation. This duplication creates an inherent risk of drift, with security properties being updated in two places, with the OpenAPI view of OAuth often often much less rich than say - for example - OAuth Server Metadata. +> +> Security Scheme Objects therefore potentially create a tight coupling between a given Operation Object (or the entire API description) and a snapshot of the OAuth configuration for that Operation. This approach served older versions of the OpenAPI Specification adequately enough, but the evolution of the security space and the creation of profile-based OAuth and OpenID Connect specification, such as the [FAPI 2.0 Security Profile](https://openid.net/specs/fapi-security-profile-2_0-final.html), has resulted in a significant gap between what the OpenAPI Specification can describe, and what such security profiles need to describe to API consumers. + +The analysis above describes the current "state of the union" in the OpenAPI Specification viz. how API security, especially complex profiles like the FAPI security profiles, are currently supported. Profile like FAPI cannot be described in a clear and authoritative manner, because OpenAPI lacks sufficient richness to describe them. However, "porting" all objects from a profile like FAPI to OpenAPI is almost certainly not the answer, because this creates a maintenance overhead for allowing OpenAPI to keep pace with changes to a security profile. + +A middle ground is therefore required that allows the OpenAPI Specification to "carry" a suitably deterministic vocabulary that defines the objects that apply to a given API Operation whilst still allow flexibility and portability. Taking the example of the FAPI 2.0 profile mentioned above, API security actually breaks down into many complex relationships, as shown in the following (AI-generated) diagram: + +![Overview of FAPI 2.0 Components - Generated by Claude](./fapi2_security_profile_normative_references.svg) + +Clearly representing all the RFC and BCPs here in the OpenAPI Specification is going to be impossible to achieve _in full_, but the Specification should be able to do "just enough" to provide a view of the security requirements that can do the following provide enough information for a Client to bootstrap the security requirement, and then potentially source data through external references to generate an appropriate representation (to be expanded on below...) + +There is also a need to not "throw the baby out with the bath water" in that create completely flexible specifications with few deterministic references does nothing to grow the OpenAPI "brain", in that features to come cannot leverage existing features. Going back to OAuth Flow Objects, these are actually a great feature to have, but leveraging them implies a fixed metadata footprint, in that `tokenUrl` **must** be supplied in all Flow objects and for example `authorizationUrl` must be declared for the `authorizationCode` Flow object. The shape of the object is therefore not manifestly incorrect, but the **_placement of the metadata is._**, especially in conjunction with security profiles like FAPI 2.0 where OAuth Server Metadata or OpenID Discovery are a very real and widely deployed part of the approach. "Security metadata" must therefore be abstracted away from the OpenAPI Specification itself, and encapsulated by appropriate rules to ensure values can be deterministically sourced. + +We also have industry-specific needs that reflect how API security profiles are used in the real world. Going back to FAPI 2.0 again, while the FAPI Working Group maintains the core specification many jurisdictions define a local profile that tailors the constraints for the local market and sets out mandated or out of scope elements of the core specification, for example the [UAE Security Profile](https://openfinanceuae.atlassian.net/wiki/spaces/standardsv2dot1final/pages/702414912/Security+Profile+-+FAPI), which is then subject to certification. Being able to create a clear underlying definition of FAPI 2.0 in OpenAPI Specification **_and_** being able to inherit that profile for given market would be a massive boost for API consumers and providers alike. + +The proposal herein therefore sets out the approach to achieving a revised Security Profile approach that achieve a number of goals reflecting the discussion above, namely: + +- Allow complex security requirements to be modeled effectively, providing sufficient information to humans or machines to understand the construct or infer requirements in code from the security requirement. +- Allow API security requirements to be incorporated in the OpenAPI Specification in a modular way. +- Ensure that all security metadata is provided by means that reflect the salient approaches for discovery by clients. +- Allow security profiles to be reused by API providers, either directly or through industry standards bodies. + +The approach to achieving these goals is described in the following sections. + +## Proposed solution + +One of the key goals above is to allow a security description to be developed in a modular way, with increasing levels of granularity and configurability. The basis of this approach is as follows: + +1. A separate, dedicated OpenAPI Security Specification (OSS), referenced by the OpenAPI Specification is created to carry objects that are specifically for API security. The OSS will nominally be developed under the banner of a Standardized API Feature (SAF), but this is subject to discussion with TSC and more work on evolving the approach to ensure it is the right framework for delivery. +2. One-or-more features can be brought together to create a Security Profile, using the OSS as the main vocabulary but declaring them as a standalone specification. Examples of a Security Profile would be FAPI 1.0 Advanced, or FAPI 2.0. +3. A given Security Profile can also be tailored to fit customization frequently found in industry profiles, as discussed above, which is published in an Ecosystem Registry. Examples of a Registry entry would be the local FAPI security profiles found in open banking and open finance jurisdiction like Brazil, KSA, UAE, and UK. + +The features of the approach all support creating an OpenAPI description document that declares _explicitly_ the security requirements for a given API Operation. In terms of "where stuff goes", the following describes the general (and non-exhaustive) approach. + +| Item | Type | Maintained By | +| --- | --- | --- | +| RFC describing a security feature, either encapsulating the entire RFC or through a normalized object | OpenAPI Security Specification | Security SIG | +| Security feature with additional constraints on an RFC | Security Profile Framework | Security Profile | +| A constrained or tailored version of a Security Profile | Ecosystem Registry | Ecosystem Team | +| An API description that enforces security requirements for a given resource (that is describes) | OpenAPI Description Document | Standards Owner or API Provider | + +The sections below expand on the approach and the shape of the proposed features. + +### OpenAPI Security Specification + +The first step defining a solution for Security Profiles is to create a separate OSS. + +The rational for doing this is threefold: + +1. The current OpenAPI Specification is already long and packed with information. Extending it for new, extensive subject matter is likely to make it even more dense. +2. API security constructs are dense in themselves. Adding a dense subject matter to an already dense OpenAPI Specification is likely to cause future pain as users and editors deal with the subject matter. +3. Modularity would allow security objects to evolve at their own pace, creating a useful loose coupling between aspects of the overall OpenAPI Specification. + +Standardized security objects provides the means to describe objects that are a primitive of a given security schema, and are therefore open to a common solution. Fundamentally this does not differ to existing Security Scheme Objects, but the approach in the context of a SAF and the focus on runtime resolution means that + +An example of this is a JSON Web Token (JWT). JWTs are protocol-bound through [JOSE](https://datatracker.ietf.org/wg/jose/about/) and [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519) and are limited in their implementation by characteristics such as the encoding method and "shape" of the object. Providing a defined object for JWTs will help ensure adherence to the underlying RFC whilst still providing information about the shape of the API. + +The table below provides a list of candidate objects, some of which overlap with existing Security Scheme Objects (for which there will need to be a suitable approach to deprecating, in readiness for a future major version). All of these objects will be expanded upon in the [Detailed Design](#detailed-design) section. + +> **Please note that this list may include objects that already have some representation in existing versions of the OpenAPI Specification. The list is intended to provide candidate features and how to deal with existing Security Scheme Object variants needs to be discussed and agreed by TSC and the active community participants.** + +| Object | Description | Rationale | +| --- | --- | --- | +| Discovery | Describes a metadata discovery endpoint | Commonly implemented in API security frameworks. Provides affordances for multiple security approaches. | +| MTLS | Describes a Mutual TLS configuration, including trust anchor and certificate chain validation requirements, that can be applied to client authentication or sender-constrained access tokens. | Provides and anchor for declaring a given MTLS profile, where ciphers, Trust Anchors, and enrolment instructions can be declared. Client authentication via mTLS and mTLS-bound access tokens (RFC 8705) are both first-class mechanisms in FAPI 2.0, so a standardized object is needed alongside JSON Web Token to cover the non-JWT authentication and sender-constrained paths. | +| JSON Web Token | Describes a JSON Web Token (JWT), covering both its encoding/structure and its claims, regardless of whether it is used as a Client Assertion, a DPoP proof, a signed request object, or an ID Token. | JWTs are protocol-bound through [JOSE](https://datatracker.ietf.org/wg/jose/about/) and [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519), and the encoding/shape and claims are properties of the same object regardless of role. A single standardized object avoids duplicating that structure across the various JWT uses, while still ensuring adherence to the underlying RFC. | +| Credential | Describes an artifact presented by the client to authenticate itself to the AS or resource server, independent of its encoding. For example, a Client Assertion under `private_key_jwt` (RFC 7523) would be a Credential whose value is shaped by the JSON Web Token object. | Not every JWT is a credential, and not every credential is a JWT (e.g. `tls_client_auth`/`self_signed_tls_client_auth` authenticate via the MTLS object instead). A DPoP proof, for instance, is a JWT but proves possession of a key bound to a token/request rather than asserting client identity, so it is not a Credential. Separating "this authenticates the client" from "this is how a JWT is shaped" avoids conflating authentication semantics with encoding, and lets a Credential be backed by whichever underlying object (JSON Web Token, MTLS) the auth method actually uses. | +| Access Request | Describes the parameters of a request that carries structured information about the access being sought, independent of the surrounding protocol envelope. | Named directly after GNAP's own `access` terminology ([RFC 9635](https://www.rfc-editor.org/info/rfc9635/)), since GNAP's Grant Request has no separate "authorization request" step to attach structured content to. The name is not a stretch for FAPI 2.0 either — Rich Authorization Request ([RFC 9396](https://www.rfc-editor.org/info/rfc9396/)) describes the same shape, a typed, structured description of what's being asked for, just riding inside an OAuth Authorization Request rather than standing alone. | +| Token | Describes a token issued to the client that is intended to be consumed for its context, rather than treated as an opaque bearer credential — for example an OpenID Connect ID Token. Built on the JSON Web Token object, but scoped to the claims a client is expected to read and validate locally (e.g. `iss`, `sub`, `aud`, `nonce`, `acr`, `auth_time`, and profile-specific claims). | Access Tokens are deliberately opaque to the client under OAuth 2.0, but ID Tokens (and similar context-carrying tokens) are explicitly meant for client-side parsing and validation. Without a dedicated object, there is no deterministic way to describe what an ID Token looks like for a given API, forcing clients to fall back on generic OIDC assumptions rather than what the API/profile actually issues. | +| Pushed Authorization Request (PAR) | Explicitly describes [RFC 9126](https://www.rfc-editor.org/info/rfc9126/), which is a mechanism to transport an Access Request with appropriate encapsulation to an Authorization Server | PAR is a mandatory building block of FAPI 2.0, is an optional component of FAPI 1.0 Advanced, and is being included in other OpenID related protocols. Adding this to the OSS seems a sensible move, based on adoption. | +| OAuth Profile | Describes a given OAuth grant type, but using discovery and object references to drive the shape of the object. The OAuth Profile object references other objects described above to provide enough information to the client to understand the security constraints applied to a given resource. | + +### Security Profile Framework + +The Security Profile Framework is the means to describe a security profile or security feature in a way that does not automatically affect other parts of the OpenAPI Specification. + +Taking a high-level example, the Security Profile for FAPI 2.0 would leverage the vocabulary of the OSS and then add addition constraints, for example: + +- Specific ciphers prescribed by [RFC 9325](https://www.rfc-editor.org/info/rfc9325/#section-4.2) that are applied to a MTLS Object (incorporated in FAPI through BCP 195). +- Minimum TLS protocol version prescribed by [RFC 9325](https://www.rfc-editor.org/info/rfc9325/#section-4.1) that is applied to a MTLS Object (incorporated in FAPI through BCP 195). +- Certificate trust anchor and chain validation requirements (not the chain itself) prescribed by [RFC 5280](https://www.rfc-editor.org/info/rfc5280/) that are applied to a MTLS Object. +- Mandatory claims parent object claims that encapsulate an Access Request Object, prescribed by [RFC 9101](https://www.rfc-editor.org/info/rfc9101/) (JAR), that are defined in the context of an OAuth Profile Object. + +The Security Profile therefore provides an _extension point_ for the core OSS. The advantages of this approach are as follows: + +- Nominally leverages the proposed introduction of the Standardized API Features (SAF) framework. +- Will allow a given Security Profile to move at its own pace, and solicit engagement from like-minded groups of experts. +- _Potentially_ allows for an alternative lexicon to be supported without tainting the core OpenAPI Specification or the baseline OSS. + +### Ecosystem Registry + +The Ecosystem Registry is the means to describe a locally tailored variant of a Security Profile, published and maintained by the standards body or ecosystem responsible for a given jurisdiction or industry vertical, rather than by the Security Profile's own working group. + +Taking a high-level example, the FAPI 2.0 Security Profile is maintained centrally by the FAPI Working Group, but individual open banking and open finance jurisdictions — Brazil, KSA, UAE, and UK among them — layer their own constraints on top for local certification, such as the [UAE Security Profile](https://openfinanceuae.atlassian.net/wiki/spaces/standardsv2dot1final/pages/702414912/Security+Profile+-+FAPI). A Registry entry for a jurisdiction like this would typically: + +- Mandate elements that the parent Security Profile leaves optional, for example requiring `certificateBoundAccessTokens` on the MTLS Object where FAPI 2.0 permits DPoP as an alternative sender-constraining mechanism. +- Mark elements of the parent Security Profile as out of scope for the local market, for example ruling out a Credential type that isn't recognized by the local Trust Framework. +- Substitute local references in place of generic ones, for example pointing the MTLS Object's trust anchor at a jurisdiction-specific root CA, or the Discovery Object at a local regulator's well-known endpoint. + +The Ecosystem Registry therefore provides a second, narrower _extension point_, layered on top of a Security Profile in the same way a Security Profile is layered on top of the OSS. The advantages of this approach are as follows: + +- Allows a single, canonical Security Profile (e.g. FAPI 2.0) to be maintained once by its working group, with jurisdictional variance kept out of the core definition. +- Allows ecosystems such as open banking and open finance bodies to publish and certify against their own tailored profile without forking or duplicating the underlying Security Profile. +- Keeps the certification boundary explicit: conformance to a Registry entry implies conformance to its parent Security Profile, plus whatever constraints are layered on top, mirroring the "Maintained By" separation set out in the [table above](#proposed-solution) (Security SIG → Security Profile → Ecosystem Team). + +## Detailed design + +The sections below are intended to provide the following: + +1. Highlight design constraints I have attempt to implement through writing this proposal. +2. Outline the objects the OSS will implement. +3. Use FAPI 2.0 and GNAP to show how the objects and the design constraints can be implemented in practice. + +The target outcome is to ensure that readers can fully comprehend the core structure of OSS, how a profile is overlaid, and the "shape" of the proposed objects. + +### Design Constraints + +The table below provides the high-level design constraints used in this proposal. + +| Principle | Rationale | +| --- | --- | +| An RFC that describes a security feature or protocol in normative terms is represented in the OSS | OSS should carry an expansive vocabulary. The Security Profile Framework is reserved for processing instructions or additional constraints a specific profile layers on top of that vocabulary. | +| JWTs are not just data. | JWTs represent processing behaviors as well as data, and therefore need a specific object with deterministic scope to be correctly represented in OpenAPI. | +| Security features must be normalized wherever possible to provide consistent object models | Provides consistent object naming practices and prevents sprawl | +| All features, where applicable, must provide a strong programmatic indicate of what the underlying RFC or security profile | Provides humans and agents a clear and deterministic reference of the underlying corpus of knowledge that can be used for reference or inference | + +### Key Design Feature: The `implements` Property + +As is evident from the FAPI 2.0 RFC map above, security specifications and profiles are a composite of many RFCs. However, different RFCs can also represent the same feature or function of a specification, as is evident from the OAS and especially existing Security Scheme objects. As per the [Design Constraints](#design-constraints) it also makes sense to normalize objects, as regardless of their provenance having a standardized object for a given common feature reduces sprawl and cognitive load for humans. + +There is also a question of "signaling" what a given object relates to i.e. how can a given object make it abundantly clear what the underlying security constraint is? + +This proposal puts forth the idea of the `implements` property, which will define the underlying RFC, BCP, or Security Profile to which a given object relates. `implements` will be an enumerated list of values, defined by either the OSS or a Security Profile, that provides a deterministic pointer to what the security constraint aligns to. Humans and/or agents will use this as a hook to provide or infer context, so as to make informed decisions about how to interpret the security constraint. + +> Note that using `implements` in this way is only intended to be a high-level indicator, to ensure that there is a valid pointer to a source of truth. Reviewers should ask themselves this question: Is this enough? Do humans and agents need more context, in order to process the underlying requirements? This feedback is key to helping progress this proposal. + +In the sections below the proposed object shapes will show the use of `implements` and how it is leveraged in the examples provided. + +### OpenAPI Security Specification Objects + +This section provides a view of the proposed objects that require definition in the OSS to support proposed initiatives such as FAPI 2.0 and GNAP. + +The list is by no means exhaustive, in that other objects could be defined based on either ecosystem demands or existing GitHub Issues (for example, CBOR support in OpenAPI has been mooted). + +Each object is framed as both a YAML example and what it _delivers to the client_, which in the sense of the security **_must_** be as close as possible to fully automated. + +> **As a reminder, some of these objects may overlap with existing Security Scheme Object variants. The way forward in managing a migration away from Security Scheme Objects to their "replacements" in the OSS will be discussed with TSC and subject to community feedback.** + +#### Discovery Object + +A Discovery Object provides scaffolding for client bootstrapping, where the client needs to retrieve security configuration at runtime. + +For example, the following is an OIDC-compatible Discovery Object, with per-environment values: + +```yaml +OAuthMetadataDiscovery: + implements: Rfc8414 + urls: + - type: Development + url: https://example.com/discovery/dev/.well-known + - type: Production + url: https://example.com/discovery/prod/.well-known +``` + +Where: + +- `implements` specifies the type of discovery document, adhering to a given RFC (in this case [OAuth 2.0 Authorization Server Metadata](https://www.rfc-editor.org/info/rfc8414)). +- `endpoints` provides one or more discovery urls and descriptions (additional metadata could be carried here). + +There is a strong argument that a `metadataProperties` property could be added that describes the available properties in the Discovery endpoint, but there is no supported protocol or approach for specifying this, so OpenAPI would be providing something genuinely esoteric that may be difficult for tooling makers to adopt. + +#### MTLS Object + +An MTLS Object describes a Mutual TLS configuration, including trust anchor and certificate chain validation requirements, that can be applied to client authentication or sender-constrained access tokens. + +The following is an example MTLS Object in an OAD that enforces TLS Client Authentication: + +```yaml +TlsClientAuthentication: + implements: Rfc8705 + trustAnchorUrl: https://example.com/trustAnchor.ca + onboardingInstructionsUrl: https://example.com/docs/onboarding-instructions +``` + +Where: + +- `implements` indicates compliance with [RFC 8705](https://www.rfc-editor.org/info/rfc8705/) client authentication via a CA-issued certificate. +- `trustAnchorUrl` points to the certificate chain required to validate the server certificate. +- `onboardingInstructionsUrl` is where onboarding instructions are provided (Onboarding for clients can be nebulous or obfuscated, and a simple URL seems sensible in lieu of a typical or protocol-bound mechanism) + +Note that consideration was given here to a `certificateBoundAccessTokens` parameter (of a `boolean` type), but this was discarded as it is declared by [discovery](https://www.rfc-editor.org/info/rfc8705/#name-example-authorization-serve). The supported cipher suite and minimum TLS version are deliberately absent here, as these are profile-level constraints applied via the Security Profile Framework, and not part of the base shape. + +#### JSON Web Token Object + +A JSON Web Token Object describes a the core requirements of a given instance of a JWT, covering both its encoding/structure and its claims, regardless of whether it is used as a Client Assertion, a DPoP proof, a signed request object, or an ID Token. + +Existing historic issues, particularly [#37](https://github.com/OAI/sig-security/issues/37) describe why addressing JWT support directly in the OpenAPI Specification is a "good thing". Proposals are described compatible with v3.1 onwards (due to JSON Schema features available), but defining a JWT as a Schema Object does nothing to convey _processing instructions_ to turn a string that is a JWT, JWS, or JWE into a header (for validation), a JSON payload (for parsing), and a signature (for validation of the header and the payload). + +That said, the shape of a given object remains relatively simple. The proposed object shape is: + +```yaml +AuthorizationRequestJwtProperties: + implements: Rfc9101 + headerSchema: + $ref: "#/components/schemas/AuthorizationRequestHeaderProperties" + payloadSchema: + $ref: "#/components/schemas/AuthorizationRequestPayloadProperties" +``` + +Where: + +- `implements` indicates adherence to a JWT-Secured Authorization Request (that's RFC 9101). +- `headerSchema` is the expected JWT Header format: + - This is a Schema Object. + - This is **_intentionally extensible_**, for reasons that will become clear in the alignment sections below. +- `payloadSchema` is the expected JWT Payload shape: + - This is a Schema Object. + +Note here that there are no "special" indicators for a given signing algorithm or other cryptographic constraint. The idea is to define the shape of the JWT - so serialization and deserialization happen in an expected and structured way - put the supported _constraints_ on the JWT are applied **_by Discovery and by the Security Profile Framework_**. + +In the example above the `implements` flag defines a specific flavour of a JWT that indicates the shape, as an indicator of the processing instructions prescribed for creating or verifying a JWT under RFC 9101. For the sake of _absolute clarity_, here this means the `request` parameter value that is carried in the request payload described by this RFC. The top-level payload itself is URL-form encoded, and not a JWT, and the `implements` flag in this case should not be taken to mean the entire RFC, just the JWT-related portions. + +This shape also lends itself to fulfilling FAPI 2.0 requirements, because `implements` can be replaced by `Fapi2SecurityProfile`, where specific algorithms are prescribed for the JWT signature. Again, this "hint" is then resolved by discovery (there is choice based on [this clause](https://openid.net/specs/fapi-security-profile-2_0-final.html#section-5.4.1-2.1.1)). + +This shape fit with the idea of making runtime decisions based on the shape of the object and metadata that informs the Client or agent about the shape. The JSON Web Token Object defines that shape - probably the most significant missing piece of the puzzle in the OpenAPI Specification - and then the `implements` hint and discovery addresses the processing options. + +#### Credential Object + +A Credential Object describes an artifact presented by the client to authenticate itself to the Authorization Server or Resource Server. + +The example above describes a Client Assertion as described by [RFC 7521], which is implemented in a Pushed Authorization Request ([RFC 9126](https://www.rfc-editor.org/info/rfc9126/)) and used in FAPI 2.0. + +For this example the proposed object shape in an OAD is as follows: + +```yaml +ClientAssertionProperties: + implements: Rfc7521 + type: jwtBearer + jwtSchema: + $ref: "#/components/jsonWebTokens/ClientAssertionJwtProperties" +``` + +Where: + +- `implements` indicates adherence to RFC 7521 as a means to indicate expected shape of the credential and processing instructions. +- `jwtBearer` indicates compliance with RFC 7523, the underlying framework that defines the JWT shape and processing instructions. + - This informs the client that `client_assertion_type` is set to `urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer` (URL encoded). +- `jwtSchema` is a JSON Web Token Object, which encapsulates the required directives for creating and verifying the Client Assertion. + - The object in the snippet is the `ClientAssertionJwtProperties`, which **does not** define a Access Request Object, only the Credential itself. + - `jwt` should most like be a `oneOf` with the other options being a plain Schema Object, which requires feedback from reviewers (human or AI) on whether this is sensible. + +The abstraction of a Credential Object in this way is design to ensure a separation of concerns in dependent objects. This will be illustrated in the shape of the Pushed Authorization Request, with an example [below](#pushed-authorization-request). + +#### Access Request Object + +An Access Request Object describes the parameters of a request that carries structured information about the access being sought by the client. This is a common pattern in all FAPI variants (an Authorization Request, passed with by reference, in Authorization Code Flow, or through a Pushed Authorization Request) and a core construct of GNAP. + +The example below shows a simple example of the proposed shape in an OAD based on [Rich Authorization Requests (RAR)](https://www.rfc-editor.org/info/rfc9396/): + +```yaml +OpenFinanceAccessRequest: + implements: Rfc9396 + schema: + $ref: "#/components/schemas/RichAuthorizationRequestBody" +``` + +Where: + +- `implements` points to RFC 9396, which defines that the `authorization_details` parameter carries the RAR. +- `payload` describes the content of `authorization_details`. + +For clarity, alternative values here could be `Rfc9635`, indicating compliance with GNAP access requests, but more on this below in the GNAP alignment section. + +Note important design decision here. Under FAPI 2.0 the Access Request is encapsulated as a JAR, which is inherently a JWT structure. + +Separating concerns between an Access Request and a JSON Web Token does not make massive sense here, so it may make sense simply point to a JSON Web Token Object and avoid using an Access Request. Overlaying a JSON Web Token Object on an Access Request seems semantically complex: A JSON Web Token can represent the Access Request with no real overhead, and it'd be easier for tooling and users to understand the semantics. + +#### Token Object + +A Token Object describes a token issued to the client that is intended to be consumed for its context, rather than treated as an opaque bearer credential. + +```yaml +IdTokenAsDetachedSignature: + type: idToken + schema: + $ref: "#/components/jsonWebTokens/IdTokenJwtProperties" +``` + +Where: + +- `idToken` indicates compliance with the [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) ID Token. +- `schema` is a JSON Web Token Object reference. + +Tokens that are completely opaque (Access Tokens under core RFC 6749, for example) would be defined as a `string`, as a fallback to a simple Schema Object for a "simple" token format. + +#### Pushed Authorization Request + +The object definition for PAR brings together several of the objects described above to describe the requirements for a Authorization Request. + +The example below shows how a PAR is implemented in an OAD: + +```yaml +PushedAuthorizationRequest: + credential: + $ref: "#/components/credentials/ClientAssertionProperties" + parameterName: request + parameterFormat: + $ref: "#/components/jsonWebTokens/AuthorizationRequestJwtProperties" +``` + +Where + +- `credential` describes the presented credential to authenticate the client, in this case a reference to the `ClientAssertionProperties` object defined above. +- `parameterName` indicates that the `request` parameter is sent in the payload, which is transported using URL encoded form parameter. +- `parameterFormat` is the payload sent in `request`, in this case a JSON Web Token Object that describes the required header, payload, and encapsulates the properties that could also be represented in an Access Request, as described above (a design decision for discussion). + +Note the absence of an `implements` flag here. A Pushed Authorization Request is "self-describing" and denormalized, in that it encapsulates all of RFC 9126, so `implements` is considered unnecessary. + +#### OAuth Profile + +An OAuth Profile Object describes a specific OAuth 2.0 grant type end-to-end — endpoint resolution, how the request is staged, and any OAuth-bound mechanics such as PKCE — by composing references to the objects described above, rather than restating protocol details inline. This is the OSS replacement for the existing Security Scheme OAuth Flow Object, where a Flow Object requires a fixed metadata footprint (`tokenUrl`, `authorizationUrl`, etc). This approach removes the close coupling with OAS, as the current implementation requires these parameters regardless of whether that data already exists at a discovery endpoint. The OAuth Profile Object resolves that footprint from a Discovery Object at runtime instead. + +The OAuth Profile object is **key** in this list of examples because **this is what performs the function of the Security Scheme and is referenced as a Security Requirement**. + +The example below shows an Authorization Code grant in an OAD: + +```yaml +AuthorizationCodeProfile: + implements: Rfc6749 + type: authorizationCode + discovery: + $ref: "#/components/security/OAuthMetadataDiscovery" + authorizationRequest: + $ref: "#/components/authorizationRequests/PushedAuthorizationRequest" + pkce: false + scopes: + - account:read + - account:write +``` + +Where: + +- `implements` indicates adherence to [RFC 6749](https://www.rfc-editor.org/info/rfc6749/), the base OAuth 2.0 authorization framework this profile is describing. +- `type` selects `authorizationCode` from OAuth 2.0's grant type registry. + - This mirrors the same pattern used by the Credential Object's `type: jwtBearer`: `implements` names the governing framework, `type` selects a specific flavour from within it. + - Other grant types (`clientCredentials`, `refreshToken`, and so on) would each be described as their own OAuth Profile Object instance, rather than folding every grant type into a single object with fields that only apply to some of them. + - A Security Profile can then extend this list to provide other values (for example `ciba`, although strictly speaking CIBA is an OpenID Connect profile). +- `discovery` is a Discovery Object reference, resolved at runtime rather than restated as static `tokenUrl`/`authorizationUrl` values. +- `authorizationRequest` is optional at the base OSS level, and references a Pushed Authorization Request (or an Access Request Object directly, where PAR isn't in play). + - The `authorizationRequest` tells a client which shape to expect when staging the request; nothing in the base object requires it to be set. +- `pkce` indicates whether Proof Key for Code Exchange ([RFC 7636](https://www.rfc-editor.org/info/rfc7636/)) applies to this grant. As with `authorizationRequest`, this field exists on the base object because PKCE is an OAuth-bound mechanism, only forcing its value to `true` as a Security Profile concern. + +This shape lends itself to fulfilling FAPI 2.0 requirements, in the same way described for the JSON Web Token Object above. Under the Security Profile Framework, `implements` on this same object can be replaced with `Fapi2SecurityProfile`, at which point `authorizationRequest` becomes mandatory (a bare Authorization Code grant has no PAR requirement, so is not FAPI 2.0 compliant without it) and `pkce` is fixed to `true`. This is explored further in the FAPI 2.0 alignment section below. + +#### Referencing the OpenAPI Security Specification + +The final point to raise in this section is how OSS would referenced in an OAD. + +Based on previous discussions at TDC and the use of SAFs, this is expected to be as an `extends` clause, similar to the snippet below: + +``` +openapi: 3.3.0 +extends: + - OpenAPISecuritySpecification +``` + +Where `OpenAPISecuritySpecification` indicates the OSS. Clients or tools would resolve this indicator to a given SAF, and use that as a reference for parsing the OAD in question. + +> This approach requires greater discussion at TDC. While it approximately reflects the discussion with [Henry Andrews](https://github.com/handrews) on his ideas on the SAF framework, this likely needs to firming up into a more concrete shape, once this proposal has been progressed. + +### Alignment to Proposal: FAPI 2.0 Security Profile + +The objects described above map almost entirely to the objects required for FAPI 2.0. However, the objects described need color adding to them, to describe the specific shape and constraints that FAPI 2.0 applies. + +This is the _raison d'etre_ for the Security Profile Framework, in that it allows a Profile to be developed that extends OSS and then adds specific clauses. + +The expectation is that the Security Profile Framework is formed of two artefacts: + +- A specification document that describes the additional constraints. +- A JSON Schema document that: + - Applies those constraints, as far as is practical, to the shape of OSS objects. + - Adds new objects where the OSS does not hold them. + +As an example of the constraints in question, the following are a sample taken from the FAPI 2.0 Security Profile at [Section 5.3.3.2-1](https://openid.net/specs/fapi-security-profile-2_0-final.html#section-5.3.3.2-1), which are constraints for the Client that are **enforced** by the Authorization Server. An annotation of how they are resolved is provided for each constraint. + +| Clause | Approach | Explanation | +| --- | --- | --- | +| _shall use the authorization code grant described in [RFC6749]_ | JSON Schema | Enforced in JSON Schema but disallowing other grant types | +| _shall use pushed authorization requests according to [RFC9126]_ | JSON Schema | Authorization Request mandatory on the OAuth Profile Object and must be a Pushed Authorization Request | +| _shall use PKCE [RFC7636] with S256 as the code challenge method_ | JSON Schema and Discovery | `pkce` set as a `const` to `true` in JSON Schema, Discovery provides `code_challenge_method` parameter only supporting `S256` | +| _shall generate the PKCE challenge specifically for each authorization request and securely bind the challenge to the client and the user agent in which the flow was started_ | N/A | Client runtime concern | +| _shall check the iss parameter in the authorization response according to [RFC9207] to prevent mix-up attacks_ | N/A | Client runtime concern | +| _shall only send client_id and request_uri request parameters to the authorization endpoint (all other authorization request parameters are sent in the pushed authorization request according to [RFC9126])_ | OAD? | Could be enforced by the OAD itself that implements the profile - for discussion | +| if using [OIDC], should not use nonce parameter values longer than 64 characters | N/A | Client runtime concern | + +Based on the annotations above the enforcement of Client constraints as list above can therefore be **_explicitly represented_**, where applicable in a Security Profile. A FAPI 2.0 Security Profile would be published to the Ecosystem Registry and referenceable in a given OAD: + +``` +openapi: 3.3.0 +extends: + - Fapi20SecurityProfile +``` + +The example below then shows how an OAuth Profile would be expressed in an OAD, with `profile` indicating additional constraints are imposed by the `Fapi20SecurityProfileAuthCodeFlow` Security Profile (the explicit naming is intentional by the way, as there is likely to be a `Fapi20SecurityProfileClientCredentialsFlow` in the making): + +```yaml +AuthCodeFlow: + implements: Fapi20SecurityProfileAuthCodeFlow + type: authorizationCode + discovery: + $ref: "#/components/discovery/OAuthWellKnown" + mtls: + $ref: "#/components/mtls/TrustFrameworkCertificate" + authorizationRequest: + $ref: "#/components/authorizationRequests/PushedAuthorizationRequest" + scopes: + - account:read + - account:write +``` + +Where: + +- `profile` points to the Authorization Code grant type declared by the FAPI 2.0 Security Profile. +- `type` is set to `authorizationCode`, which is retained due to the potential addition of a Client Credentials profile soon. +- `discovery` is a Discovery Object. +- `mtls` is the MTLS Object that defines the required certificate profile. +- `authorizationRequest` is mandated to be a Pushed Authorization Request, based on the Security Profile JSON Schema applying this constraint. +- As discussed above, `pkce` is removed completely as it is mandatory. +- `scopes` are as before, but additional constraints could be applied (but this is enough detail for an example). + +This example is almost certainly incomplete, but provides an clear and deterministic view of how a Security Profile can overlay (no, not an Overlay) the OSS. Once clear and obvious addition, not added for the sake or brevity, is a [DPOP (RFC 9449)](https://datatracker.ietf.org/doc/html/rfc9449), which is effectively a Credential Object, implementing a JWS. + +Again, and for the avoidance of doubt: **This is what defines the security requirements for a given resource, and is intended to provide sufficient information to the Client to scaffold code to adhere to security constraints imposed by the Security Profile to access that resource.** + +### Alignment to Proposal: GNAP + +GNAP is unlike FAPI 2.0 in that GNAP is not a profile of OAuth 2.0 (RFC 9635 states explicitly that _"GNAP is not an extension of OAuth 2.0 and is not intended to be directly compatible with OAuth 2.0."_) + +GNAP is therefore effectively a standalone security protocol and, based on the Design Constraints [above](#design-constraints), should fit into in the OSS directly. Taking this approach has merit, for the following reasons: + +- **Provenance**: Adding a GNAP Object allows extension out of the box, as part of the core OSS vocabulary. +- **Extensibility**: Should industry or ecosystem initiatives come along that leverage GNAP a security profile can be created from OSS using the Security Profile Framework (ideally published to the Ecosystem Registry). + +OSS therefore appears to be the right "home" for GNAP. Based on the objects described above, an initial release of the OSS should have built-in support for the following GNAP building blocks (extended beyond the examples described above): + +- **Discovery**: GNAP intentionally aims to limit discovery in its design, instead using one-or-more grant requests that allow Clients to be granted access to a given resource. However, "seeding" is required to understand the capabilities of the Authorization Server, and a [Discovery section](https://www.rfc-editor.org/info/rfc9635/#name-discovery) describes the supported parameters. +- **Access Request**: The Access Request Object fits semantically into the space described by grant requests in GNAP, in that JSON payloads describe the access being requested from the GNAP Authorization Server. While these could adequately be described in core OAS, this does not make for a clear security enforcement pattern. Using Access Requests as a standalone object with different GNAP flavours seems sensible. +- **MTLS**: While GNAP supports negotiation to an `mtls` proof, the features already highlighted above in actually creating an appropriate key and signed certificate are not defined in GNAP itself. An MTLS Object therefore can fulfill this function. +- **JSON Web Tokens**: JSON Web Tokens, particularly JSON Web Signatures are implemented as a proof of possession approach in GNAP, both as a payload and as a detached signature. The proposed JSON Web Token Object can therefore provide the shape of the proof of possession (although there is a question where this lives, as the claims are mandated. Does it make sense to put in an OAD, or express it directly in OSS?) + +There are other objects that are not covered in the examples above, however, the merit consideration as additional standalone objects. For example, HTTP Signatures are defined as a proof of possession mechanism alongside those discussed above. JSON Web Keys are used to define signing keys. However, GNAP oftentimes gives examples of these objects provided in grant requests - therefore fundamentally just a Schema Object, described by an Access Request - so having dedicated objects in OSS to support GNAP may be redundant from the outset. + +These additional objects highlighted above actually raises a key design decision for GNAP: What belongs in the OSS and what belongs in an OAD? This requires iteration with TDC to ensure the correct and most appropriate separation of concerns in GNAP support. + +The extensibility of GNAP - multiple proofing mechanisms, multiple interaction methods, optional bearer tokens - means that, exactly as with OAuth and FAPI 2.0, a specific ecosystem building on GNAP will still need a Security Profile to be deployable and certifiable. None of this is needed to support GNAP itself — it only applies once a concrete GNAP-based profile exists: + +- Restricting which proofing mechanism(s) are permitted (e.g. mandating `httpsig` only, or forbidding `bearer` tokens so all access tokens are key-bound). +- Restricting which interaction start/finish methods are permitted (e.g. mandating `redirect`/`redirect` only, ruling out `user_code` for machine-to-machine clients). +- Mandatory or forbidden fields within the Grant Request (e.g. requiring specific `resource_references`, or subject-identifier claims), in the same way FAPI 2.0 mandates claims within a signed Request Object via [RFC 9101](https://www.rfc-editor.org/info/rfc9101/) (JAR). +- Reusing, unchanged, the existing MTLS Object constraints (ciphers, TLS version, trust anchor) wherever `mtls` proofing is selected. + +It is therefore envisaged that as interest in GNAP proliferates and GNAP-based security profiles are created they will be fully compatible with the proposal described in this document. + +## Backwards compatibility + +This proposal is based on an entirely new Security Specification, and is therefore considered to have very low impact on the OAS as it stands. + +OAS will need to be updated to accommodate references to either the core OSS or a Security Profile, which is considered the main area of impact. + +## Alternatives considered + +No alternatives considered at this time, due to the fact this is a fairly comprehensive proposal with many moving parts. + +The intention is to open this up to review, and then challenge the parts of the proposed design piece by piece, to reduce cognitive load and seek consensus on specific items. + +## Outstanding Design Considerations + +| Consideration | Rationale | Answer | +| --- | --- | --- | +| Best approach to Security Scheme Objects and new OSS objects co-existing | Need consensus on best approach, especially in terms of "what to use" for a given security requirement. Ideally the OAS would be instructive enough to indicate preference | | +| Discuss options for implementing GNAP | What is split between the OSS and an OAD in terms of the description of grant requests, especially in view of underlying security features and how they are expressed | | +| Components of a Security Profile | Do the proposed components make sense (specification, JSON Schema document) or are alternatives required | | diff --git a/proposals/fapi2_security_profile_normative_references.svg b/proposals/fapi2_security_profile_normative_references.svg new file mode 100644 index 0000000000..6a79c50274 --- /dev/null +++ b/proposals/fapi2_security_profile_normative_references.svg @@ -0,0 +1,60 @@ +FAPI 2.0 Security Profile and its related specificationsA hub-and-spoke map with FAPI 2.0 at the centre. Solid lines connect required specifications: OAuth 2.0 core, the OAuth security BCP, TLS recommendations, pushed authorization requests, PKCE, authorization server metadata, and three one-of choices for client authentication, sender-constrained tokens and authorization response integrity. Dotted lines connect optional specifications: JAR, OpenID Connect, RAR, JWT access tokens, introspection and revocation, and message signing. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RFC 6749 / 6750OAuth 2.0 + bearer +RFC 9700 (BCP 240)OAuth security BCP +RFC 9325 (BCP 195)TLS recommendations + +RFC 9126Pushed auth requests +RFC 7636PKCE, S256 only +RFC 8414AS metadata + +Client authmTLS 8705 / JWT 7523 +Sender-constrainedmTLS 8705 / DPoP 9449 +Response integrityiss 9207 / JARM + +FAPI 2.0 Security ProfileOpenID Foundation + +RFC 9101JAR request objects +OpenID Connect coreIdentity layer +RFC 9396Rich auth requests + +RFC 9068JWT access tokens +RFC 7662 / 7009Introspect, revoke +Message signingJAR, JARM, RFC 9421 + + +Required + +Optional or profile-dependent +