Skip to content

Instantly share code, notes, and snippets.

@akrabat
Created August 19, 2025 11:24
Show Gist options
  • Save akrabat/b69c23ab935caa5cd27f257aa0d775f5 to your computer and use it in GitHub Desktop.
Save akrabat/b69c23ab935caa5cd27f257aa0d775f5 to your computer and use it in GitHub Desktop.
Convert public keys published in JWKS to PEM format
#!/usr/bin/env -S uv run --script --quiet
# /// script
# dependencies = [
# "cryptography",
# ]
# ///
"""Convert JWK keys to PEM format.
This script reads .well-known/jwks.json and outputs PEM encoded versions
of the public keys in that file.
This file should be set as executable (chmod +x jwk-to-pem.py).
Usage:
curl -s https://example.com/.well-known/jwks.json | jwk-to-pem.py
uv run jwk-to-pem.py jwks.json
uv run jwk-to-pem.py < jwks.json
Requirements:
- uv (https://github.com/astral-sh/uv)
- cryptography library
Author:
Rob Allen <[email protected]>
Copyright 2025
License:
MIT License - https://opensource.org/licenses/MIT
"""
import json
import base64
import sys
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
def base64url_decode(data):
"""Decode base64url to bytes"""
# Add padding if needed
padding = 4 - len(data) % 4
if padding != 4:
data += '=' * padding
# Replace URL-safe chars
data = data.replace('-', '+').replace('_', '/')
# Decode
return base64.b64decode(data)
def jwk_to_pem(jwk_key):
"""Convert JWK to PEM format"""
if jwk_key['kty'] != 'RSA':
raise ValueError("Only RSA keys are supported")
# Decode the modulus (n) and exponent (e) to int
n = int.from_bytes(base64url_decode(jwk_key['n']), 'big')
e = int.from_bytes(base64url_decode(jwk_key['e']), 'big')
# Create RSA public key
public_key = rsa.RSAPublicNumbers(e, n).public_key()
# Serialize to PEM
pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
return pem.decode()
def main():
if len(sys.argv) > 2:
print("Usage: jwk_to_pem.py [jwks.json]")
print("If no file is provided, reads from stdin")
sys.exit(1)
if len(sys.argv) == 2 and sys.argv[1] != '-':
# Read from file
with open(sys.argv[1], 'r') as f:
jwks = json.load(f)
else:
# Read from stdin
jwks = json.load(sys.stdin)
# Convert each key
for i, key in enumerate(jwks['keys']):
kid = key.get('kid', f'key-{i}')
print(f"# Key {i} (kid: {kid})")
print(jwk_to_pem(key))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment