def sign(payload, priv_key_json): priv = jwcrypto.jwk.JWK.from_json(priv_key_json) jws = jwcrypto.jws.JWS(payload) # TODO(supersat): Is there a better way to do this? jws.add_signature(priv, protected=json.dumps({ "alg": "RS256", "jwk": json.loads(priv.export_public()) })) return jws.serialize()
def issue_token(self, intended_audience: str, scopes: List[str]) -> str: # Construct request body query = { 'grant_type': 'client_credentials', 'client_id': self._client_id, 'scope': ' '.join(scopes), 'resource': intended_audience, 'current_timestamp': datetime.datetime.utcnow().isoformat() + 'Z', } payload = '&'.join([k + '=' + v for k, v in query.items()]) # Construct JWS token_headers = { 'typ': 'JOSE', 'alg': 'RS256', 'x5u': self._cert_url, 'kid': self._kid, } jws = jwcrypto.jws.JWS(payload.encode('utf-8')) jws.add_signature(self._private_jwk, 'RS256', protected=jwcrypto.common.json_encode(token_headers)) signed = jws.serialize(compact=True) # Check JWS jws_check = jwcrypto.jws.JWS() jws_check.deserialize(signed) try: jws_check.verify(self._public_jwk, 'RS256') except jwcrypto.jws.InvalidJWSSignature: raise AccessTokenError( 'Could not construct a valid cryptographic signature for JWS') # Construct signature signature = re.sub(r'\.[^.]*\.', '..', signed) # Make token request request_headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'x-utm-message-signature': signature, } response = requests.post(self._token_endpoint, data=payload, headers=request_headers) if response.status_code != 200: raise AccessTokenError( 'Request to get SignedRequest access token returned {} "{}" at {}' .format(response.status_code, response.content.decode('utf-8'), response.url)) return response.json()['access_token']