Skip to content

feat: Readiness for informal feedback - #1

Closed
SensibleWood wants to merge 1 commit into
mainfrom
feat/proposal-security-profiles
Closed

SensibleWood wants to merge 1 commit into
mainfrom
feat/proposal-security-profiles

Conversation

@SensibleWood

@SensibleWood SensibleWood commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

⚠️ This is an informal, pre-PR sounding board — not the official proposal submission. The goal is to stress-test the approach and gather early feedback from the community/TSC before this is raised as a formal proposal PR. Expect gaps, open questions, and design decisions still up for debate — see the "Outstanding Design Considerations" table at the end of the proposal for a running list.

Summary

Adds proposals/2026-09-18-Security-Profiles.md, a proposal for decoupling security requirements from the core OpenAPI Specification so that complex, profile-based security models — starting with FAPI 2.0 and GNAP — can be described explicitly and deterministically, rather than approximated through today's Security Scheme / OAuth Flow objects.

The core problem: OAuth Flow Objects require a fixed, static metadata footprint (tokenUrl, authorizationUrl, etc.) that duplicates the real source of truth (OAuth Server Metadata / OIDC Discovery), risks drift, and has no room to express the additional constraints that profiles like FAPI 2.0 layer on top of plain OAuth 2.0.

Proposed approach

A three-layer model, each layer with a clear owner:

Layer Purpose Maintained by
OpenAPI Security Specification (OSS) A separate, dedicated vocabulary of security primitives (JWT, MTLS, Credential, Access Request, Token, PAR, OAuth Profile, Discovery, etc.), each grounded in a specific RFC Security SIG
Security Profile Framework Additional constraints a specific profile (e.g. FAPI 2.0) layers on top of the OSS vocabulary Security Profile working group
Ecosystem Registry Jurisdiction/industry-specific tailoring of a Security Profile (e.g. UK/Brazil/KSA/UAE Open Banking variants of FAPI 2.0) Ecosystem team

Highlights:

  • A catalog of candidate OSS objects (Discovery, MTLS, JSON Web Token, Credential, Access Request, Token, Pushed Authorization Request, OAuth Profile), each with a worked YAML example.
  • An implements property, used consistently across objects to point at the underlying RFC, BCP, or Security Profile an object instance conforms to — giving both humans and agentic tooling a deterministic hook back to the source of truth.
  • A set of explicit design constraints (e.g. "JWTs are not just data," structured request/consent content is always by reference to a Schema Object, never embedded in the OSS or Security Profile layers).
  • Worked alignment sections showing how the model maps onto FAPI 2.0 (via the Security Profile Framework) and GNAP (which, being a standalone protocol rather than an OAuth profile, is proposed to live largely in the OSS itself).

What feedback is most useful right now

  • Does the OSS / Security Profile Framework / Ecosystem Registry split make sense, and is the "who maintains what" division right?
  • Is the implements property the right mechanism for signaling RFC/profile compliance?
  • Reactions to the specific object shapes (particularly Access Request vs. JSON Web Token overlap, and the still-open questions around GNAP's Discovery/Access Request split).
  • Anything in the "Outstanding Design Considerations" table at the end of the proposal.

Checklist

  • schema changes are included in this pull request
  • schema changes are needed for this pull request but not done yet
  • no schema changes are needed for this pull request

🤖 Generated with Claude Code

@handrews

Copy link
Copy Markdown

@SensibleWood could you add a complete OAD example showing how this all fits together with real endpoints, and walk through how a tool is expected to process the instructions? Given that the focus is on giving tools enough information to perform the auth, I'd like to understand exactly how that works with a realistic OAD.

@handrews handrews left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot here that I really like, including semantics-by-reference-to-RFC wherever possible. I have noted a few questions or points of confusion. None of them are necessarily objections at this time, I'm mostly trying to understand the step-by-step process tools will take to use these things.


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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defining a JWT as a Schema Object does nothing to convey processing instructions

I agree that schemas are not well-suited to signaling behavior, but this seems to be relying on schemas for everything that "implements" does not nail down. This is something we struggled with when it comes to HTTP headers in general: are we giving tooling an indication of what actions it needs to be able to take, or are we validating data?

How much of what needs to be done here is signal-reading/processing instructions vs data validation?


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:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our approach so far has been that OADs indicate which SAFs they are using. SAFs are more like libraries than base classes.

Comment on lines +423 to +425
| _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` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inspecting schemas for these sorts of things is simple if the schema is written in just the right way, but even schemas that do simple things can be written in arbitrarily complex ways, e.g. having many references to follow to find the right part of the schema, or following allOf to collect everything that applies to the same thing but from different subschemas. It might be easier to have specific fields indicating behavior. Otherwise, to make this feasible we would probably have to put a lot of restrictions on what kind of schemas can be written. Which might work, but might be a bit un-intuitive.


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.

@handrews handrews Sep 22, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't entirely understand this. OSS is the OpenAPI Security Specification, correct? Meaning the document produced in the SIG-Security repository as a companion to the OAS, which is a very different thing from an OpenAPI Description (OAD). Did you mean what goes in OSS vs OAS?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. For GNAP the split here looks more like OSS versus a Security Profile than OSS versus an OAD, given the claims at 484 are already fixed.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@handrews @lj-raidiam I've addressed this in the soon to be released proposal with expanded text. Its become a question of OSS vs Security Profile vs OAD because it is not clear how normative a grant request specification is. I've dropped in Open Payments GNAP implementation as an example.

OAuthMetadataDiscovery:
implements: Rfc8414
urls:
- type: Development

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a multi-party ecosystem the API description is published centrally (by a scheme operator, regulator or industry body, ...) and implemented by many providers, each running its own authorization server. Endpoints are resolved per provider at runtime, from a directory or from the provider's own metadata, which is why descriptions in these ecosystems carry authorizationUrl: https://authserver.example/authorization placeholders today. The publisher can't know the URLs.

So: who fills this in, and when? Worth exploring whether the object needs a way to say "resolved per provider" rather than carrying a URL at all.

authorizationRequest:
$ref: "#/components/authorizationRequests/PushedAuthorizationRequest"
pkce: false
scopes:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scopes sit on the profile object here, but today this is per-operation i.e. the Security Requirement Object carries the scope list and Operation security overrides the root. If this object is itself referenced as a Security Requirement (line 358), do the two coexist or does one replace the other?

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This subordinates the Access Request to a staging slot, while scopes sits as a first-class field. FAPI 2.0 recommends RAR where scope isn't expressive enough, and RAR is used in ecosystems today. It is worth thinking about how authorization_details sits on the profile too.


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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems to draw the right boundary on trust, but it's worth making it explicit as a general rule, because trustAnchorUrl at 223 crosses it. An OAD is unsigned and routinely bundled and overlaid, so it can carry trust requirements but shouldn't be where a client sources trust material.


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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. For GNAP the split here looks more like OSS versus a Security Profile than OSS versus an OAD, given the claims at 484 are already fixed.


```yaml
OAuthMetadataDiscovery:
implements: Rfc8414

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A tiny one from me on payload styling:

Suggested change
implements: Rfc8414
implements: RFC8414

I suggest that we align the capitalisation of these enum values with the official standards they refer to (e.g., using all-caps RFC8414 rather than mixed-case Rfc8414 or lowercase rfc8414).

If references like OWASP-ASVS-4.0 or NIST-SP-800-53 are introduced later, keeping the prefixes capitalised makes them much easier to read when scanning data payloads or logs. While official web namespaces like urn:ietf:rfc:8414 technically use lowercase for network routing, forcing all profiles into lowercase (like owasp-asvs-4.0) compromises human scannability.

Standardising on uppercase constants provides the best balance: it matches industry conventions for API enums, maintains readability across non-IETF profiles, and automated tools can still easily lowercase the string to build a URN path if needed.

@SensibleWood

Copy link
Copy Markdown
Owner Author

@handrews @lj-raidiam @cjrobbertse-ob thanks so much for the comments on this. Where required I will migrate outstanding comments over to the new, official PR: OAI/sig-security#54

I have incorporated some comments into the proposal text as direct quotes, as this to me makes sense from a provenance perspective in the changes I have acted on.

Closing this, going over there from now on...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants