Project: MongoDB (App Definition and Development / Database)
File: README.JWT.md

At present, usage of JWS in MongoDB is limited to the Linux platform only and is not implemented on other platforms. Since signature validation is not available on other platforms, use of the unvalidated JWT types, while present, is not useful. JWK (JSON Web Key): A human readable representation of a cryptographic key. See JSON Web Key Note: This library currently supports based keys only. JWS (JSON Web Signature): A cryptographic signature on a JWT, typically presented as a single object with the token and a header. See JSON Web Signature Note: This library currently supports the only. JWT (JSON Web Token): A JSON object representing a number of claims such as, but not limited to: bearer identity, issuer, and validity. See JSON Web Token loads `JWKSet`s from an HTTPS endpoint, parses the received JSON using the `JWKSet`, `JWK`, and `JWKRSA` types from IDL, and instantiates with the key material. Later, when validating a client supplied token, the application will use the type with a `JWKManager` to validate the token. `JWK`: The base key material type in IDL. This parses only the `kid` (Key ID) and `kty` (Key Type) fields. In order to expect and process key specific data, the `kty` must already be known, therefore type specific IDL structs are defined as chaining the base `JWK` type. `JWKRSA`: Chains the base `JWK` type and adds expected fields `n` and `e` which represent the modulus and public-exponent portions of the RSA key respectively. `JWKSet`: A simple wrapper struct containing a single field named `keys` of type `array<object>`. This allows the class to load a `JWKSet` URI resource and pull out a set of keys which are expected to conform to the `JWK` interface, and as of this writing, represent `JWKRSA` data specifically. These types, as well as and can be found in . A typical JSON file containing keys may look something like the following: ```json { "keys": [ { "kid": "custom-key-1", "kty": "RSA", "n": "ALtUlNS31SzxwqMzMR9jKOJYDhHj8zZtLUYHi3s1en3wLdILp1Uy8O6Jy0Z66tPyM1u8lke0JK5gS-40yhJ-bvqioW8CnwbLSLPmzGNmZKdfIJ08Si8aEtrRXMxpDyz4Is7JLnpjIIUZ4lmqC3MnoZHd6qhhJb1v1Qy-QGlk4NJy1ZI0aPcuNEUM7lWhPAJABZsWc6MN8flSWCnY8pJCdIkcAktA0U17tuvVduuFX94763nWYikZIMJScTQMMVxYNMf1xcNNOVFlUSJHYHClk46QT9nT8FWeFlgvvWhlXfhsp9aNAi3pX-KxIxqF2wABIAKnhlMa3CJW41323Js", "e": "AQAB" }, { "kid": "custom-key-2", "kty": "RSA", "n": "ANBv7-YFoyL8EQVhig7yF8YJogUTW-qEkE81sbs2CTsI1oepDFNAeMJ-Krfx1B7yllYAYtScZGol60R9Ou4X89LA66bnVRWVFCp1YV1r0UWtn5hJLlAbqKseSmjdwZlLe420GlUAiyYsiIr6wltC1dFNYyykq62RhfYhM0xpnt0HiN-k71y9A0GO8H-dFU1WgOvEYMvHmDAZtAP6RTkALE3AXlIHNb4mkOc9gwwn-7cGBc08rufYcniKtS0ZHOtD1aE2CTi1MMQMKkqtVxWIdTI3wLJl1t966f9rBHR6qVtTV8Qpq1bquUc2oaHjR4lPTf0ZhTaELJa5-BBbvJU", "e": "AQAB" } ] } ``` The interface provides a platform agnostic API for verifying the signatures on `JWS` signed `JWT` payloads. Each instance of a `JWSValidator` is created (via `JWSValidator::create`) with a specific key, and may have it's `JWSValidator->validate()` invoked multiple times (concurrently) to validate tokens as they are received from third parties such as connected clients. Platform specific implementations of the cryptographic functions may be found in: Linux: Windows: UNIMPLEMENTED macOS: UNIMPLEMENTED Non-TLS builds: UNIMPLEMENTED A token MUST NOT be trusted from any third party unless its contents have been duly validated. The `JWSValidatedToken` exists to encapsulate the processing of a signed token into usable fields while maintaining a type on the post-processed token as well. An application will construct a `JWSValidatedToken` by passing both a signed and a . The token's header is parsed using IDL type to determine the `kid` (Key ID) which was used for signing. The is queried for a suitable

If the requested `kid` is unknown to the , it will requery its `JWKSet` URI to reload from the key server. That validator is used to check the provided signature against the header and body payload. The body of the token is parsed using IDL type . Relevant validity claims `nbf` () and `exp` () are verified. If, at any point during this construction, an error is encountered, a `DBException` will be thrown and no `JWSValidatedToken` will be created. Callers MUST validate `iss` (Issuer) and `aud` (Audience) independently. Callers SHOULD only retain `JWSValidatedToken` objects. To access fields, use the `getBody()`/`getBodyBSON()` accessors on an as-needed basis from the `JWSValidatedToken` object rather than storing these values by themselves. This ensures that the data being used has been validated. Directly parsing the signed JWS compact serialization using any other means than `JWSValidatedToken` should be considered an error and rejected during code review. A typical Compact Serialization string, as received from a third party, may look something like the following: ``` eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImN1c3RvbS1rZXktMSJ9. eyJpc3MiOiJodHRwczovL3Rlc3Qua2VybmVsLm1vbmdvZGIuY29tL29pZGMvaXNzdWVyMSIsInN1YiI6InVzZXIxQG1vbmdvZGIuY29tIiwibmJmIjoxNjYxMzc0MDc3LCJleHAiOjIxNDc0ODM2NDcsImF1ZCI6WyJqd3RAa2VybmVsLm1vbmdvZGIuY29tIl0sIm5vbmNlIjoiZ2RmaGpqMzI0ZWhqMjNrNCIsIm1vbmdvZGItcm9sZXMiOlsibXlSZWFkUm9sZSJdfQ. nhM7C5oHy1jRT4we1oFBpzzBQ7e8ccZdUvtua6d5C4wg0W2Kf3Vf2ze7VTRzq1CdIeemlx0YuzxNoE1ujZI9W9zRZJmBWhahZHG-MYqtFioz-fZvAjHdK8VhLKF2wrvRBlFDNbJtPzIdF3dT1hnfYv4ASwCgEVZJA2CrPmTTnbgVoqWhyiGUWK-DtNhHRVVIXjXkV-f6bor2Oipp0EP2ukY30LNnBQm-cBIB01Q91PZHRHkG\\CtayFILWSdpZPGwOlO3yjUVw0lMdoAYamUPGfjNOQooFyevdHNGuvbh8nqQPgf5ZmRYP7EUJ9\_DipoV4q90TMHQi9pXjc72zSLJg ``` As described in , this is divided into three sections delimited by periods. The first section in our example is the `base64url::encode()` output of the `JWSHeader` represented as `JSON`, so it would decode as: ```json {"typ": "JWT", "alg": "RS256", "kid": "custom-key-1"} ``` This tells us that the payload in the second field of the compact serialized signature is a `JWT` (this is currently expected to always be the case). We also see that the `alg`orithm for signing uses (`RSASSA-PKCS1-v1_5 using SHA-256`) and that the signature can be verified using the key material associated with `custom-key-1`. The IDL struct `JWSHeader` may be used to parse this section for access to the relevant `alg` and `kid` fields. See also: JOSE Header In the second of the three sections, we have the `JWT` token body itself, again encoded using `base64url` on a `JSON` representation. So in this example, it would decode as: ```json { "iss": "https://test.kernel.mongodb.com/oidc/issuer1", "sub": "user1@mongodb.com", "nbf": 1661374077, "exp": 2147483647, "aud": ["jwt@kernel.mongodb.com"], "nonce": "gdfhjj324ehj23k4", "mongodb-roles": ["myReadRole"] } ``` The IDL struct `JWT` will be used to parse this section by , however token payloads SHOULD NOT be inspected without processing them through the validating infrastructure. See JWT Claims Note that this token payload contains an additional field not defined by any RFC or ietf-draft. The content of this, or any other unknown fields is treated as opaque and ignored by as applications are permitted to define additional fields provided they are uniquely named. For information on how a field like `mongodb-roles` is used, refer to the `MONGODB-OIDC architecture guide`. The third and final section of a JWS Compact Serialization is a non human-readable output of a cryptographic signing operation as defined by the payload's `JWSHeader`. In this case, `RS256` is specified as the signing `alg`orithm which roughly translates to computing the SHA256 digest of the header, delimiting period, and payload sections, then transforming the signature output (with PKCS#1v1.5 padding) using an RSA private key. We validate this signature by transforming the digest output back out using our RSA public key and comparing that to our locally produced digest output. The heavy lifting of this operation is handled internally by OpenSSL on linux.