OAI / OpenAPI-Specification

The OpenAPI Specification Repository
https://openapis.org
Apache License 2.0
29.01k stars 9.07k forks source link

Support describing security keys in OAS #1881

Open whitlockjc opened 5 years ago

whitlockjc commented 5 years ago

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:

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.

whitlockjc commented 5 years ago

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?

MikeRalphson commented 5 years ago

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?

whitlockjc commented 5 years ago

Agreed. I want the top-level security key properties to be implementation agnostic.

cmheazel commented 5 years ago

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.

whitlockjc commented 5 years ago

I'm not following, JWS already has a "JWT-like" structure where the algorithm and key details are describes. So what's missing?

cmheazel commented 5 years ago

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.

whitlockjc commented 5 years ago

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.

fosrias commented 4 years ago

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

SensibleWood commented 4 years ago

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

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