Skip to content

Instantly share code, notes, and snippets.

@leondutoit
Last active May 11, 2021 09:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leondutoit/a9b0ba333f46f0db45fb5b00fda6e33c to your computer and use it in GitHub Desktop.
Save leondutoit/a9b0ba333f46f0db45fb5b00fda6e33c to your computer and use it in GitHub Desktop.
pseudo-code for returning claims from userinfo endpoint as a signed JWT
"""
Pseudocode for implementing returning claims obtained from the /userinfo
OIDC endpoint, as a signed JWT. The spec describes this here:
https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
"If the UserInfo Response is signed and/or encrypted, then the Claims are
returned in a JWT and the content-type MUST be application/jwt."
"""
from jwcrypto import jwt, jwk
def make_asymmetric_signed_jwt(config: dict, claims: dict) -> str:
key = jwk.JWK.from_json(config.get('id_token_signature_key'))
kid = json.loads(key).get('kid')
token = jwt.JWT(
header={'alg': 'RS256', 'kid': kid},
claims=claims,
)
token.make_signed_token(key)
return token.serialize()
def user_info(config: dict, user_info_return_type: str, claims: dict) -> tuple:
if user_info_return_type == 'json':
return claims, 'application/json'
elif user_info_return_type == 'jwt':
return make_asymmetric_signed_jwt(config, claims), 'application/jwt'
# to use this in a HTTP request to /userinfo
# one would, do something like this:
config = {
'id_token_signature_key': 'some-key', # <- private key (RSA-SHA256s) would go here
}
request_headers = get_request_headers()
client_config = get_client_config(request_headers)
claims = get_claims_for_user(request_headers)
payload, headers = user_info(config, client_config.get('user_info_return_type'), claims)
write_http_response(
headers={'Content-Type': headers},
payload=payload,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment