https://auth0.com/docs/secure/tokens/json-web-tokens/locate-json-web-key-sets
To convert a JWKS (JSON Web Key Set) `x5c` (X.509 certificate chain) to PEM format in Python, you can use libraries like `cryptography` and `base64`. The `x5c` parameter contains the certificate chain in base64-encoded DER format, and you need to decode it to convert it into PEM format.
Here's a step-by-step guide and the corresponding Python code:
### Step-by-Step Process
1. **Install Necessary Libraries**: You need the `cryptography` library to handle the certificate conversion. If it's not installed, you can install it using pip:
```bash
pip install cryptography
```
2. **Import Libraries**: Import the necessary libraries for handling base64 and cryptography functions.
3. **Extract the x5c Certificate**: Extract the first certificate from the `x5c` array. This is typically the leaf certificate that you want to convert.
4. **Decode the Base64 Certificate**: Decode the base64-encoded certificate from the `x5c` array.
5. **Convert to PEM Format**: Use the `cryptography` library to convert the decoded certificate to PEM format.
6. **Print or Save the PEM**: Print or save the PEM format certificate as needed.
### Example Code
Here is the complete Python code to perform the conversion:
import base64 from cryptography import x509 from cryptography.hazmat.primitives import serialization # Sample JWKS x5c entry jwks = { "keys": [ { "kty": "RSA", "use": "sig", "kid": "1b94c", "x5t": "1b94c", "x5c": [ "MIIDQzCCAqygAwIBAgIGANiDqDRzMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMRYwFAYD VQQKEw1FeGFtcGxlIEluYy4xEDAOBgNVBAsTB0V4YW1wbGUxEDAOBgNVBAMTB0V4YW1wbGUxHTAb BgkqhkiG9w0BCQEWDmV4YW1wbGUuY29tMB4XDTExMDEwMTAwMDAwMFoXDTIxMDEwMTAwMDAwMFow YjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUV4YW1wbGUgSW5jLjEQMA4GA1UECxMHRXhhbXBsZTEQ MA4GA1UEAxMHZXhhbXBsZTEdMBsGCSqGSIb3DQEJARYOZXhhbXBsZUBleGFtcGxlLmNvbTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8AP6o6LzW68FZXF4c3gU1q4szU2NyZf2fsBF2x 7L8Hi7vh5PS3LVC1b9nkg4QQoVROv4iHCJPC6vQL1Pjk7Xb48tcdiR8H5E0pHpZZy7yRQU5R4ZSy hmXP8KszV39um7ROnPEA0iE7okFOqhFKaBFPQ8x4+8bRbLNRvT+Ajc8Vq0XZJHJs4H0kCkgvB3T1 VLk0t3ZXMyZ7RHZ8o5JZmjdsKEzxv5kjFWzQXoX66Kq3KUD44C5tNqIl4HN6mygrm0P2HFz3txa6 Oq65LqJYVJ+Gdi5q9NVJggJlD2lD7q3BGN45SGH56uB7g6t5sUdL0z4MeTmOhJX7PqBaTyPYMCOU RIECAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQIwDQYJKoZIhvcN AQEFBQADggEBABRmaQoea2f32wGxdm/S4JN7r2nV0Dk54RCeyyptc6FZp4U9gKm3aIDR4/XHWH/k +X9G4BgqOqaDOP1g6Txz+1WlKHeaN1x6fUpxvtwutVJW0GgM4K6g/7p9cq7YFDmaXlDXD5w1Un5x k1lw20h3f2RVOJ9vDafhe2l7r4+a1Q+YYPOFhA2N0L5nBWVndppkOnUKu+EXr3nJpxzTNWs3mB4c ES7Cke+IOJJ8/x4hy9RRMZf7zBB9F3vWeKBlQpAapStn6w3xqPi3PjFq5uJ3/p0YEekEVC6E3l5z +f9AubS1Zz7TzL2P+8KFPwxg2SvF0V9hHD+XllXU5P8Cd6ShnwqKpjQ=", # Add additional certificates if needed ] } ] } def convert_x5c_to_pem(jwks): # Get the first x5c entry x5c_base64 = jwks["keys"][0]["x5c"][0] # Decode the base64-encoded certificate x5c_der = base64.b64decode(x5c_base64) # Load the certificate using cryptography certificate = x509.load_der_x509_certificate(x5c_der) # Convert the certificate to PEM format pem_certificate = certificate.public_bytes(serialization.Encoding.PEM) return pem_certificate.decode("utf-8") # Convert and print the PEM format certificate pem_certificate = convert_x5c_to_pem(jwks) print(pem_certificate)
Note:
### Explanation
1. **Import Libraries**: The code uses `base64` for decoding and `cryptography` for handling certificate conversions.
2. **Extract the x5c Certificate**: The first certificate in the `x5c` array is extracted. It's common to convert only the leaf certificate, but you can handle the entire chain if needed.
3. **Decode the Certificate**: The `base64.b64decode()` function decodes the base64-encoded string into DER format, which is the binary format for X.509 certificates.
4. **Load and Convert the Certificate**: The `cryptography.x509.load_der_x509_certificate()` function loads the DER-encoded certificate, and then it's converted to PEM format using the `public_bytes()` method with `serialization.Encoding.PEM`.
5. **Output**: The PEM format certificate is returned as a UTF-8 string and printed.
### Output
The output will be a PEM-formatted certificate like this:
```plaintext
-----BEGIN CERTIFICATE-----
MIIDQzCCAqygAwIBAgIGANiDqDRzMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYT
AlVTMRYwFAYDVQQKEw1FeGFtcGxlIEluYy4xEDAOBgNVBAsTB0V4YW1wbGUxEDAO
...
k1lw20h3f2RVOJ9vDafhe2l7r4+a1Q+YYPOFhA2N0L5nBWVndppkOnUKu+EXr3nJ
pxzTNWs3mB4cES7Cke+IOJJ8/x4hy9RRMZf7zBB9F3vWeKBlQpAapStn6w3xqPi3
PjFq5uJ3/p0YEekEVC6E3l5z+f9AubS1Zz7TzL2P+8KFPwxg2SvF0V9hHD+XllXU
5P8Cd6ShnwqKpjQ=
-----END CERTIFICATE-----
```
### Handling Certificate Chain
If you need to convert the entire certificate chain, you can iterate over all entries in the `x5c` array:
def convert_x5c_chain_to_pem(jwks): pem_chain = [] for cert_base64 in jwks["keys"][0]["x5c"]: # Decode the base64-encoded certificate cert_der = base64.b64decode(cert_base64) # Load the certificate certificate = x509.load_der_x509_certificate(cert_der) # Convert to PEM pem_certificate = certificate.public_bytes(serialization.Encoding.PEM) pem_chain.append(pem_certificate.decode("utf
import jwt from jwt import PyJWTError, InvalidTokenError, ExpiredSignatureError, InvalidSignatureError, InvalidAudienceError from cryptography.hazmat.primitives import serialization # Sample token and public key token = "your.jwt.token.here" public_key = """ -----BEGIN PUBLIC KEY----- YOUR_PUBLIC_KEY_HERE -----END PUBLIC KEY----- """ def validate_jwt_rs256(token, public_key): try: # Decode the token #If the aud claim on the token is set (on yours it is set to 'some-aud') then decoding MUST specify an expected aud value using the audience argument for #decode() otherwise decoding will fail with an InvalidAudienceError. #Please see: https://github.com/jpadilla/pyjwt#audience-claim payload = jwt.decode( token, public_key, algorithms=["RS256"], # Use the correct algorithm options={"verify_exp": True} # Verify expiration ) # Successfully decoded token print("Token is valid.") print("Payload:", payload) return payload except ExpiredSignatureError: print("Token has expired.") except InvalidSignatureError: print("Signature verification failed.") except InvalidAudienceError: print("Invalid audience.") except InvalidTokenError: print("Invalid token.") except PyJWTError as e: print("Token validation failed:", str(e)) return None # Validate the JWT with RS256 payload = validate_jwt_rs256(token, public_key)