Often times when interacting with APIs, security keys are involved. From a JWT perspective, keys are used for encrypting, signing and verifying tokens. In issue #1464, keys are used for encrypting and signing requests/responses. I would like to propose that we officially support describing _security keys_ in OAS, starting with JSON Web Keys.
Shooting from the hip, here is a first-pass example:
# ...
components:
keys:
# Keys taken from Google's OIDC Discover Document (https://accounts.google.com/.well-known/openid-configuration)
google-oauth-v3-1:
description: "JSON Web Key used by Google for signing JWTs: https://www.googleapis.com/oauth2/v3/certs#/keys/0"
type: JWK
metadata:
kid: 0905d6f9cd9b0f1f852e8b207e8f673abca4bf75
e: AQAB
kty: RSA
alg: RS256
n: yyeEmeK35F8P54ozfpsF79n59ZsOrcZdxQWsxrzm0qjdA5r_b-be-cQnWAw_2AoGdeWHX-Cz7uPFDMdEwzLGlpv3SELi34h8PkzjyO7xlbhsNs-ICnqUyUTA7CovKtpJ47PjiQnXcaRNCFUQbli8VlEqbVLuqFjC98igICpNYR-iiVIm0VCFtkq0p8vf1yQ493Pnx2Bm8fUx6SkeJ7wKPWQq_K4e6ZH40JWLk6c1U9W5qPKeckevdNLrdZY5lsTZ5zrRvuRBoIeZfp9bKSZGMtEja4xSCDKLrkcpb4qf6Ywx9rsZ4b8eHSLpVvUzNsj3GS7qK5flHzoccovhPVBbbQ
use: sig
google-oauth-v3-2:
description: "JSON Web Key used by Google for signing JWTs: https://www.googleapis.com/oauth2/v3/certs#/keys/1"
type: JWK
metadata:
kid: a4313e7fd1e9e2a4ded3b292d2a7f4e519574308
e: AQAB
kty: RSA
alg: RS256
n: lO3_QoRd_D8UHAjFcdg0_8GOiLyWo4Viiy8cDLNGf8T1eQlqqhPYZmvGOPhyILWZ9FInOXT9AzH5KPfeOnMEzy4TqfGLtdcAlufqALe_qusmq7SSNIVfSw5iPZjzXk3BXjzoFNZLfqsoqheGzek-sJV1Ti5JQQ2hRPSZQhba9xVn6G8Uxr5ugVhHQ25P6HL4acjhuvpSPEFn7tivEIhWZEL35CeqHelf-48WA4PLzRVvfFMS-hW6erjX7uxT9mj8uT7zGl41_zBd9lMn2CQeP3aLDeQFoFaLaX2NZctRASErz6H9MIXQngM1piKnc84hmify-ZAsPpBcxw7heFpYRw
use: sig
# ...
As you can see, each key has three common properties:
description: A human-readable description of the keytype: The _type_ of the key _(One could argue that JSON Web Keys are capable of describing any key and only JSON Web Keys should be supported but for now, this value would be free-form and it would be tooling specific as to how the values are validated.)_metadata: This is the information describing the key based on the key type _(This field must be free-form to allow for future expansion)_Once we have a common way to describe security keys, you have the ability to reference them using JSON References to use. Here are two examples:
Signed Reqeusts/Responses _(#1464)_
# ...
keys:
payment-signing-key:
description: The payment signing JSON Web Key
type: JWK
metadata:
kty: EC
crv: P-256
x: PxlJQu9Q6dOvM4LKoZUh2XIe9-pdcLkvKfBfQk11Sb0
y: 6IDquxrbdq5ABe4-HQ78_dhM6eEBUbvDtdqK31YfRP8
# ...
@context: https://example.com/paymentStandard/pay,
amount: 255.00
currency: USD
signature:
# Likely unnecessary as the key describes its algorithm
alg": ES256
jwk:
$ref: "#/components/keys/payment-signing-key"
val": "RSLmFihg8QmXxM .... N0lGIdSEYvMMLTL8hEaYV9kW6A"
# ...
JWT-based Security Scheme
Note: This example uses a JWT-based Security Scheme that DOES NOT exist yet and is only for example purposes. There is an ongoing discussion about supporting JWT for security in OAS but this is not indicative of what will be supported if/when a decision is made.
# ...
components:
keys:
# Keys taken from Google's OIDC Discovery Document (https://accounts.google.com/.well-known/openid-configuration)
google-oauth-v3-1:
description: "JSON Web Key used by Google for signing JWTs: https://www.googleapis.com/oauth2/v3/certs#/keys/0"
type: JWK
metadata:
kid: 0905d6f9cd9b0f1f852e8b207e8f673abca4bf75
e: AQAB
kty: RSA
alg: RS256
n: yyeEmeK35F8P54ozfpsF79n59ZsOrcZdxQWsxrzm0qjdA5r_b-be-cQnWAw_2AoGdeWHX-Cz7uPFDMdEwzLGlpv3SELi34h8PkzjyO7xlbhsNs-ICnqUyUTA7CovKtpJ47PjiQnXcaRNCFUQbli8VlEqbVLuqFjC98igICpNYR-iiVIm0VCFtkq0p8vf1yQ493Pnx2Bm8fUx6SkeJ7wKPWQq_K4e6ZH40JWLk6c1U9W5qPKeckevdNLrdZY5lsTZ5zrRvuRBoIeZfp9bKSZGMtEja4xSCDKLrkcpb4qf6Ywx9rsZ4b8eHSLpVvUzNsj3GS7qK5flHzoccovhPVBbbQ
use: sig
# ...
security:
google-oath:
type: http
scheme: bearer
bearerFormat: JWT
jwk:
$ref: '#/components/keys/google-oauth-v3-1'
# ...
Now that we have some examples, let's get the conversation started.
I realize that we want to make this _forward thinking_ and not lock ourselves into one implementation but JSON Web Keys _(JWK)_ allow for describing all key types I interact with. So my question is can't we treat JWK as the description format for security keys and go from there?
JSON Web Keys (JWK) allow for describing all key types I interact with. So my question is can't we treat JWK as the description format for security keys
Conversely, if we find that JWKs satisfy all likely general requirements for secure-keys, can't we still use a more generic term for both the property which defines or points to one, and the same for the container within components and our definition will then 'just happen' to allow for everything a JWK needs?
Agreed. I want the top-level security key properties to be implementation agnostic.
A JWT describes a cryptographic instance. We need to describe the space of acceptable cryptographic instances. For example, an API may accept requests signed using RS256, RS384, and RS512. That would require three different JWT objects. What if we tried a JWT-like structure describing the names and valid values for the JOSE JWE and JOSE JWS parameters as well as the JWT claims? Each entry could identify the parameter/claim name and list the valid values for the entry. It should also indicate if it is protected or unprotected.
I'm not following, JWS already has a _"JWT-like"_ structure where the algorithm and key details are describes. So what's missing?
First of all, JWT describes the encryption operations that HAVE been performed. We need to describe the operations that CAN be formed. For example, how do I tell a user that they can use HS256, HS384, or HS512 to generate their signatures?
Second, OpenAPI is not restricted to JSON payloads. If I support XML signatures, how do I tell users which canonicalization algorithms my API supports?
I'm not saying that JWT is not a good place to start. But there is still more to do.
I think your crossing the streams, if I understand you correctly. I'm talking about JSON Web Keys _(JWS)_ and not JSON Web Tokens _(JWT)_. You're right about JWT, they are encrypted/signed and the JWT self-describes what was used to encrypt/sign the key. My proposal is for defining JWS _(not JWT)_ that are used for secure interactions with an API, like a JWS used to verify a JWT or like a JWS used to encrypt/sign a request/response. How an operation dictates that it's encrypted/signed, and how, is a consumer of keys and is yet to be decided. Security Schemes will need a way to consume keys as well.
@whitlockjc I think you need to expand your example to include the following (oneOf jwk or jwks_uri):
security:
jwks-oath:
type: http
scheme: bearer
bearerFormat: JWT
jwks_uri: https://example.com/.well-known/jwks.json
This then works with Oauth2 providers that use JWTs and enables using JWKs with remote look up for key rotation.
@whitlockjc I think you need to expand your example to include the following (oneOf jwk or jwks_uri):
security: jwks-oath: type: http scheme: bearer bearerFormat: JWT jwks_uri: https://example.com/.well-known/jwks.jsonThis then works with Oauth2 providers that use JWTs and enables using JWKs with remote look up for key rotation.
As an addendum to this, a good shout would be to ensure that the jwks_uri can be reflective of different environments in an API providers promotional model. For example, in the EU many banks are implementing JWKS for PSD2/open banking and they have several JWKS across their sandbox and production. For those doing OpenID Connect obvs it can be defined and exposed in Discovery endpoint but for those not this would be a good feature.
Simplest approach probably in the style of a Server object I guess
Most helpful comment
@whitlockjc I think you need to expand your example to include the following (oneOf jwk or jwks_uri):
This then works with Oauth2 providers that use JWTs and enables using JWKs with remote look up for key rotation.