From c620d8131836f6279831406c651f26965e01166c Mon Sep 17 00:00:00 2001 From: Agustin Bettati Date: Wed, 17 Jun 2026 22:27:54 +0200 Subject: [PATCH 1/3] feat(ipa): Add sensitive fields guidance in IPA-111 and OpenAPI markings in IPA-117 CLOUDP-412562 --- ipa/general/0111.mdx | 25 +++++++++++++++++++++++++ ipa/general/0117.mdx | 11 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/ipa/general/0111.mdx b/ipa/general/0111.mdx index b571d1c..165b259 100644 --- a/ipa/general/0111.mdx +++ b/ipa/general/0111.mdx @@ -71,6 +71,31 @@ the server may scale it up or down based on load. } ``` +### Sensitive Fields + +Some resource fields carry secrets — passwords, API keys, private credentials. +The API design **must** prevent accidental exposure of these values in +responses. Sensitive fields **must** be marked in OpenAPI so that consumers and +tooling can identify them (see [IPA-117](0117.mdx#sensitive-field-markings) for +the required annotations), and **must** follow one of the following +information-flow patterns: + +- **Write-only.** The client submits the value on [Create](0106.mdx) (or + [Update](0107.mdx)) and the server **must not** return it in any response. +- **Reveal-once.** For values the client cannot retrieve later (e.g. + server-generated API keys), the field **may** appear in the [Create](0106.mdx) + response so the client can capture it, but **must not** appear in subsequent + [Get](0104.mdx) or [List](0105.mdx) responses. Reveal-once is the sanctioned + exception to the [schema consistency rule](0101.mdx#resources). + +When a masked representation of a sensitive field (e.g. `****` or a last-4 +display value) needs to appear in [Get](0104.mdx) or [List](0105.mdx) responses, +it **must** be modeled as a separate read-only **redacted sibling** property +following the [Effective Values](#effective-values) pattern. The raw and +redacted values **must not** share the same property name. A redacted sibling +**may** be added to either a write-only or a reveal-once field independently of +the chosen information-flow pattern. + ### Boolean Values - Booleans **should** default to `false` diff --git a/ipa/general/0117.mdx b/ipa/general/0117.mdx index 4d1acc3..ac71b58 100644 --- a/ipa/general/0117.mdx +++ b/ipa/general/0117.mdx @@ -76,6 +76,17 @@ will promote clarity, completeness and consistency. - If the API producer needs to provide links to external documentation, they **should** use the `externalDocumentation` +### Sensitive Field Markings + +The OpenAPI `format: password` keyword identifies properties whose value is +itself a secret. To apply it consistently: + +- **Use** `format: password` on any property whose value is itself a secret per + [IPA-111 — Sensitive Fields](0111.mdx#sensitive-fields). +- **Do not use** `format: password` on a redacted sibling property whose value + is a masked display (`****`, last-4 digits, etc.). The redacted value is not + itself a secret; marking it as such misleads consumers and tooling. + ### Examples - API producers **must** provide a well-defined schema or example(s) From be2e6d476d1dce87d0cc2b5f2a2efe0c1b72fe4d Mon Sep 17 00:00:00 2001 From: Agustin Bettati Date: Fri, 19 Jun 2026 17:47:27 +0200 Subject: [PATCH 2/3] feat(ipa): Address IPA-111/117 sensitive-fields review feedback - Rename reveal-once pattern to create-response-only (API-oriented term, avoids UI 'reveal' connotation) across guideline ID, body, and references. - Add a write-only password-on-Update example to illustrate the common user-credential case. - Set IPA-117 format:password guidelines to enforcement=review (secret identification is a semantic judgment, not deterministically lintable). CLOUDP-412562 --- ipa/general/0111.mdx | 39 ++++++++++++++++++++++++++++++++------- ipa/general/0117.mdx | 4 ++-- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/ipa/general/0111.mdx b/ipa/general/0111.mdx index 0e26427..3887d4f 100644 --- a/ipa/general/0111.mdx +++ b/ipa/general/0111.mdx @@ -585,6 +585,30 @@ components: + + +```yaml +components: + schemas: + UserUpdate: + type: object + properties: + email: + type: string + password: + type: string + format: password + writeOnly: true +``` + + + When updating a user, the client submits the new `password` on + [Update](0107.mdx). It is `writeOnly: true`, so the server accepts it but + never returns it in any response. + + + + ```yaml @@ -624,13 +648,13 @@ components: - + -**Reveal-once.** For values the client cannot retrieve later (e.g. +**Create-response-only.** For values the client cannot retrieve later (e.g. server-generated API keys), the field **may** appear in the [Create](0106.mdx) response so the client can capture it, but **must not** appear in subsequent -[Get](0104.mdx) or [List](0105.mdx) responses. Reveal-once is the sanctioned -exception to the [schema consistency rule](0101.mdx#resources). +[Get](0104.mdx) or [List](0105.mdx) responses. Create-response-only is the +sanctioned exception to the [schema consistency rule](0101.mdx#resources). @@ -694,7 +718,8 @@ components: `writeOnly` to exclude it from Get and List responses. - Flag any reveal-once field that appears in Get or List response schemas. + Flag any create-response-only field that appears in Get or List response + schemas. @@ -709,8 +734,8 @@ display value) needs to appear in [Get](0104.mdx) or [List](0105.mdx) responses, it **must** be modeled as a separate read-only **redacted sibling** property following the [Effective Values](#effective-values) pattern. The raw and redacted values **must not** share the same property name. A redacted sibling -**may** be added to either a write-only or a reveal-once field independently of -the chosen information-flow pattern. +**may** be added to either a write-only or a create-response-only field +independently of the chosen information-flow pattern. diff --git a/ipa/general/0117.mdx b/ipa/general/0117.mdx index 05fc0b6..d341873 100644 --- a/ipa/general/0117.mdx +++ b/ipa/general/0117.mdx @@ -680,7 +680,7 @@ itself a secret. Guidelines below govern when to apply it. - + **Must use** `format: password` on any property whose value is itself a secret per [IPA-111 — Sensitive Fields](0111.mdx#sensitive-fields). @@ -744,7 +744,7 @@ components: - + **Must not** use `format: password` on a redacted sibling property whose value is a masked display (`****`, last-4 digits, etc.). The redacted value is not From 27a58b5bda96876ed172eecb2b8661fb0cb32d16 Mon Sep 17 00:00:00 2001 From: Agustin Bettati Date: Fri, 19 Jun 2026 18:08:06 +0200 Subject: [PATCH 3/3] fix(ipa0111): Model create-response-only with separate schemas, not writeOnly writeOnly excludes a field from all responses, including the Create response, so it cannot express a server-generated secret returned once on creation. Model it as readOnly on the Create response schema and absent from the Get and List schemas instead. CLOUDP-412562 --- ipa/general/0111.mdx | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/ipa/general/0111.mdx b/ipa/general/0111.mdx index 3887d4f..744b594 100644 --- a/ipa/general/0111.mdx +++ b/ipa/general/0111.mdx @@ -663,7 +663,8 @@ sanctioned exception to the [schema consistency rule](0101.mdx#resources). ```yaml components: schemas: - ApiKey: + # Create (POST) response: returns the secret once + ApiKeyCreateResponse: type: object properties: id: @@ -673,13 +674,21 @@ components: key: type: string format: password - writeOnly: true + readOnly: true + # Get and List response: omits the secret + ApiKey: + type: object + properties: + id: + type: string + displayName: + type: string ``` - The `key` appears only in the Create response — the client captures it once. - The `writeOnly` declaration prevents it from appearing in Get and List - responses. + The server-generated `key` appears only in the Create response schema, marked + `readOnly` since the client never sets it. The Get and List schema omits it + entirely, so the secret cannot be retrieved later. @@ -689,6 +698,7 @@ components: ```yaml components: schemas: + # Single schema reused by Create, Get, and List ApiKey: type: object properties: @@ -699,11 +709,12 @@ components: key: type: string format: password + readOnly: true ``` - The `key` lacks a `writeOnly` declaration, so the schema allows it to leak in - every Get and List response. + A single response schema carries `key` across Create, Get, and List, so the + secret is returned on every read instead of only once on creation. @@ -714,8 +725,8 @@ components: API key secret). - Confirm the field appears only in the Create response schema and is marked - `writeOnly` to exclude it from Get and List responses. + Confirm the field appears only in the Create response schema and is absent + from the Get and List response schemas. Flag any create-response-only field that appears in Get or List response