def _make_authorization_grant_assertion(self):
        """Create the OAuth 2.0 assertion.
        This assertion is used during the OAuth 2.0 grant to acquire an
        ID token.
        Returns:
            bytes: The authorization grant assertion.
        """
        now = _helpers.utcnow()
        lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
        expiry = now + lifetime

        payload = {
            'iat': _helpers.datetime_to_secs(now),
            'exp': _helpers.datetime_to_secs(expiry),
            # The issuer must be the service account email.
            'iss': self.service_account_email,
            # The audience must be the auth token endpoint's URI
            'aud': self._token_uri,
            # The target audience specifies which service the ID token is
            # intended for.
            'target_audience': self._target_audience
        }

        payload.update(self._additional_claims)

        token = jwt.encode(self._signer, payload)

        return token
Exemple #2
0
def make_refresh_authorization_grant_assertion(token_info: TokenInfo,
                                               service_accout: ServiceAccount):
    """Create the OAuth 2.0 assertion.

    This assertion is used during the OAuth 2.0 grant to acquire an
    access token.

    Returns:
        bytes: The authorization grant assertion.
    """
    now = _helpers.utcnow()
    lifetime = timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
    expiry = now + lifetime

    payload = {
        'iat': _helpers.datetime_to_secs(now),
        'exp': _helpers.datetime_to_secs(expiry),
        # The issuer must be the service account email.
        'iss': service_accout.credentials.service_account_email,
        # The audience must be the auth token endpoint's URI
        'aud': token_info.aud,
        'scope': token_info.scope,
    }

    # The subject can be a user email for domain-wide delegation.
    payload.setdefault('sub', token_info.uid)

    token = jwt.encode(service_accout.credentials._signer, payload)

    return token
def create_access_token(credentials_filename):
    credentials = service_account.Credentials.from_service_account_file(credentials_filename)

    seconds_since_epoch = int(time.time())
    # :TODO: question = do we want to hardcode # seconds to expiry?
    one_hour_in_seconds = 60 * 60
    payload = {
        'iss': credentials.service_account_email,
        'scope': 'https://www.googleapis.com/auth/datastore',
        'aud': 'https://www.googleapis.com/oauth2/v4/token',
        'exp': seconds_since_epoch + one_hour_in_seconds,
        'iat': seconds_since_epoch,
    }

    body_template = 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=%s'
    body = body_template % jwt.encode(credentials.signer, payload)

    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
    }

    response = requests.post(
        'https://www.googleapis.com/oauth2/v4/token',
        data=body,
        headers=headers)

    if httplib.OK != response.status_code:
        print 'Error generating access token'
        sys.exit(1)

    access_token = response.json()['access_token']

    return (access_token, credentials)
Exemple #4
0
    def _make_authorization_grant_assertion(self):
        """Create the OAuth 2.0 assertion.

        This assertion is used during the OAuth 2.0 grant to acquire an
        access token.

        Returns:
            bytes: The authorization grant assertion.
        """
        now = _helpers.utcnow()
        lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
        expiry = now + lifetime

        payload = {
            'iat': _helpers.datetime_to_secs(now),
            'exp': _helpers.datetime_to_secs(expiry),
            # The issuer must be the service account email.
            'iss': self._service_account_email,
            # The audience must be the auth token endpoint's URI
            'aud': self._token_uri,
            'scope': _helpers.scopes_to_string(self._scopes or ())
        }

        payload.update(self._additional_claims)

        # The subject can be a user email for domain-wide delegation.
        if self._subject:
            payload.setdefault('sub', self._subject)

        token = jwt.encode(self._signer, payload)

        return token
    def _make_authorization_grant_assertion(self):
        """Create the OAuth 2.0 assertion.

        This assertion is used during the OAuth 2.0 grant to acquire an
        access token.

        Returns:
            bytes: The authorization grant assertion.
        """
        now = _helpers.utcnow()
        lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
        expiry = now + lifetime

        payload = {
            'iat': _helpers.datetime_to_secs(now),
            'exp': _helpers.datetime_to_secs(expiry),
            # The issuer must be the service account email.
            'iss': self._service_account_email,
            # The audience must be the auth token endpoint's URI
            'aud': self._token_uri,
            'scope': _helpers.scopes_to_string(self._scopes or ())
        }

        payload.update(self._additional_claims)

        # The subject can be a user email for domain-wide delegation.
        if self._subject:
            payload.setdefault('sub', self._subject)

        token = jwt.encode(self._signer, payload)

        return token
    def _make_authorization_grant_assertion(self):
        """Create the OAuth 2.0 assertion.

        This assertion is used during the OAuth 2.0 grant to acquire an
        ID token.

        Returns:
            bytes: The authorization grant assertion.
        """
        now = _helpers.utcnow()
        lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
        expiry = now + lifetime

        payload = {
            "iat": _helpers.datetime_to_secs(now),
            "exp": _helpers.datetime_to_secs(expiry),
            # The issuer must be the service account email.
            "iss": self.service_account_email,
            # The audience must be the auth token endpoint's URI
            "aud": self._token_uri,
            # The target audience specifies which service the ID token is
            # intended for.
            "target_audience": self._target_audience,
        }

        payload.update(self._additional_claims)

        token = jwt.encode(self._signer, payload)

        return token
    def sign_jwt(self, payload):
        payload = json.loads(str(payload))
        encoded = jwt.encode(self.__signer, payload)

        if not encoded:
            return False

        return encoded.decode("utf-8")
def test_encode_extra_headers(signer):
    encoded = jwt.encode(signer, {}, header={'extra': 'value'})
    header = jwt.decode_header(encoded)
    assert header == {
        'typ': 'JWT',
        'alg': 'RS256',
        'kid': signer.key_id,
        'extra': 'value'
    }
def test_encode_extra_headers(signer):
    encoded = jwt.encode(signer, {}, header={"extra": "value"})
    header = jwt.decode_header(encoded)
    assert header == {
        "typ": "JWT",
        "alg": "RS256",
        "kid": signer.key_id,
        "extra": "value",
    }
Exemple #10
0
def generate_jwt(service_account):
    signer = crypt.RSASigner.from_string(service_account['private_key'])
    now = int(time.time())
    payload = {
        'iat': now,
        'exp': now + 3600,
        'aud': 'https://accounts.google.com/o/oauth2/token',
        'iss': service_account['client_email'],
        'scope': 'https://www.googleapis.com/auth/homegraph'
    }

    return jwt.encode(signer, payload)
Exemple #11
0
    def create_custom_token(self, uid, developer_claims=None):
        """Builds and signs a FirebaseCustomAuthToken.

        Args:
          uid: ID of the user for whom the token is created.
          developer_claims: A dictionary of claims to be included in the token.

        Returns:
          string: A token string minted from the input parameters.

        Raises:
          ValueError: If input parameters are invalid.
        """
        if not isinstance(self._app.credential, credentials.Certificate):
            raise ValueError(
                'Must initialize Firebase App with a certificate credential '
                'to call create_custom_token().')

        if developer_claims is not None:
            if not isinstance(developer_claims, dict):
                raise ValueError('developer_claims must be a dictionary')

            disallowed_keys = set(
                developer_claims.keys()) & self._RESERVED_CLAIMS_
            if disallowed_keys:
                if len(disallowed_keys) > 1:
                    error_message = ('Developer claims {0} are reserved and '
                                     'cannot be specified.'.format(
                                         ', '.join(disallowed_keys)))
                else:
                    error_message = ('Developer claim {0} is reserved and '
                                     'cannot be specified.'.format(
                                         ', '.join(disallowed_keys)))
                raise ValueError(error_message)

        if not uid or not isinstance(uid, six.string_types) or len(uid) > 128:
            raise ValueError(
                'uid must be a string between 1 and 128 characters.')

        now = int(time.time())
        payload = {
            'iss': self._app.credential.service_account_email,
            'sub': self._app.credential.service_account_email,
            'aud': self.FIREBASE_AUDIENCE,
            'uid': uid,
            'iat': now,
            'exp': now + self.MAX_TOKEN_LIFETIME_SECONDS,
        }

        if developer_claims is not None:
            payload['claims'] = developer_claims

        return jwt.encode(self._app.credential.signer, payload)
Exemple #12
0
def create_custom_token(user_id, role, token_id=None, exp=None,
                        return_payload=False):
    """
    Generate a custom JWT token signed with the Google service account's
    private key.

    Before this function can be used, `firebase_admin.initialize_app` must have
    been called.

    This implements the process described here:
    https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_a_third-party_jwt_library

    We do this manually, because the interface provided by
    `firebase_admin.auth.create_custom_token` does not allow creating tokens
    that don't expire.  This is because firebase custom tokens are intended for
    use by apps to authenticate against firebase to retrieve an identity token,
    and are really not intended to be long-lived.

    However, we are using the same process to create long-lived tokens for
    authenticating recsystems.  There's no particular harm in doing this since
    it's just our own JWT for use internally, but signed using our existing
    private key provided by the Google service account, rather than maintaining
    a separate key just for signing custom tokens.

    The other difference is we use the claim ``user_id`` instead of ``uid`` for
    the user ID, to be consistent with identity tokens generated by firebase.
    I don't know why the two token formats are inconsistent in this; it seems
    like a slight oversight on Google's part.
    """

    app = firebase_admin.get_app()
    payload = {
        'iss': app.credential.service_account_email,
        'sub': app.credential.service_account_email,
        'iat': int(time.time()),
        # google.auth's token verify requires an expiration time and always
        # validates it, so we create an exp that effectively never expires
        # before the heat death of the universe
        'exp': exp or 2**64 - 1,
        'user_id': user_id,
        # Prefix our custom claims to avoid potential future clashes
        'renewal_role': role,
        'renewal_token_id': token_id or secrets.token_hex(20)
    }

    token = jwt.encode(app.credential.signer, payload).decode('ascii')

    if return_payload:
        return (token, payload)
    else:
        return token
Exemple #13
0
def fake_token(signer):
    now = calendar.timegm(datetime.datetime.utcnow().utctimetuple())
    payload = {
        'aud': 'example.com',
        'azp': '1234567890',
        'email': '*****@*****.**',
        'email_verified': True,
        'iat': now,
        'exp': now + 3600,
        'iss': 'https://accounts.google.com',
        'sub': '1234567890'
    }
    header = {'alg': 'RS256', 'kid': signer.key_id, 'typ': 'JWT'}
    yield jwt.encode(signer, payload, header=header)
Exemple #14
0
    def factory(claims=None, key_id=None, use_es256_signer=False):
        now = _helpers.datetime_to_secs(_helpers.utcnow())
        payload = {
            "aud": "*****@*****.**",
            "iat": now,
            "exp": now + 300,
            "user": "******",
            "metadata": {
                "meta": "data"
            },
        }
        payload.update(claims or {})

        # False is specified to remove the signer's key id for testing
        # headers without key ids.
        if key_id is False:
            signer._key_id = None
            key_id = None

        if use_es256_signer:
            return jwt.encode(es256_signer, payload, key_id=key_id)
        else:
            return jwt.encode(signer, payload, key_id=key_id)
Exemple #15
0
def encode(signer, payload, header=None, key_id=None):
    """Make a signed JWT.

    Args:
        signer (google.auth.crypt.Signer): The signer used to sign the JWT.
        payload (Mapping[str, str]): The JWT payload.
        header (Mapping[str, str]): Additional JWT header payload.
        key_id (str): The key id to add to the JWT header. If the
            signer has a key id it will be used as the default. If this is
            specified it will override the signer's key id.

    Returns:
        bytes: The encoded JWT.
    """
    return jwt.encode(signer, payload, header, key_id)
def get_id_token(payload_overrides=None, header_overrides=None):
    signer = crypt.RSASigner.from_string(MOCK_PRIVATE_KEY)
    headers = {'kid': 'mock-key-id-1'}
    payload = {
        'aud': MOCK_CREDENTIAL.project_id,
        'iss': 'https://securetoken.google.com/' + MOCK_CREDENTIAL.project_id,
        'iat': int(time.time()) - 100,
        'exp': int(time.time()) + 3600,
        'sub': '1234567890',
        'admin': True,
    }
    if header_overrides:
        headers = _merge_jwt_claims(headers, header_overrides)
    if payload_overrides:
        payload = _merge_jwt_claims(payload, payload_overrides)
    return jwt.encode(signer, payload, header=headers)
Exemple #17
0
    def create_custom_token(self, uid, additional_claims=None):
        service_account_email = self.credentials.signer_email
        payload = {
            "iss": service_account_email,
            "sub": service_account_email,
            "aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
            "uid": uid
        }

        lifetime = datetime.timedelta(minutes=60)
        exp = datetime.utcnow() + lifetime
        payload["exp"] = calendar.timegm(exp.utctimetuple())

        if additional_claims:
            payload["claims"] = additional_claims

        return jwt.encode(self.credentials.signer, payload)
def fake_token(signer):
    now = calendar.timegm(datetime.datetime.utcnow().utctimetuple())
    payload = {
        'aud': 'example.com',
        'azp': '1234567890',
        'email': '*****@*****.**',
        'email_verified': True,
        'iat': now,
        'exp': now + 3600,
        'iss': 'https://accounts.google.com',
        'sub': '1234567890'
    }
    header = {
        'alg': 'RS256',
        'kid': signer.key_id,
        'typ': 'JWT'
    }
    yield jwt.encode(signer, payload, header=header)
Exemple #19
0
    def factory(claims=None, key_id=None):
        now = _helpers.datetime_to_secs(_helpers.utcnow())
        payload = {
            'aud': '*****@*****.**',
            'iat': now,
            'exp': now + 300,
            'user': '******',
            'metadata': {'meta': 'data'}
        }
        payload.update(claims or {})

        # False is specified to remove the signer's key id for testing
        # headers without key ids.
        if key_id is False:
            signer.key_id = None
            key_id = None

        return jwt.encode(signer, payload, key_id=key_id)
    def _get_signed_jwt(self):

        now = int(time.time())
        exp = now + CRED_LIFETIME_DEFAULT_SECONDS
        svc_account = self._service_account
        payload = {
            # The issuer must be the service account email.
            CLAIM_ISSUER: svc_account,
            # CLAIM_SCOPE: svc_account,
            # The audience must be the auth token endpoint's URI
            CLAIM_AUDIENCE: OAUTH_TOKEN_URI,
            TARGET_AUDIENCE: self.target_audience,
            CLAIM_ISSUED_AT: now,
            CLAIM_EXPIRE: exp
        }

        token = jwt.encode(self._signer, payload)
        return token
    def create_custom_token(self, uid, developer_claims=None, tenant_id=None):
        """Builds and signs a Firebase custom auth token."""
        if developer_claims is not None:
            if not isinstance(developer_claims, dict):
                raise ValueError('developer_claims must be a dictionary')

            disallowed_keys = set(developer_claims.keys()) & RESERVED_CLAIMS
            if disallowed_keys:
                if len(disallowed_keys) > 1:
                    error_message = ('Developer claims {0} are reserved and '
                                     'cannot be specified.'.format(
                                         ', '.join(disallowed_keys)))
                else:
                    error_message = ('Developer claim {0} is reserved and '
                                     'cannot be specified.'.format(
                                         ', '.join(disallowed_keys)))
                raise ValueError(error_message)

        if not uid or not isinstance(uid, str) or len(uid) > 128:
            raise ValueError(
                'uid must be a string between 1 and 128 characters.')

        signing_provider = self.signing_provider
        now = int(time.time())
        payload = {
            'iss': signing_provider.signer_email,
            'sub': signing_provider.signer_email,
            'aud': FIREBASE_AUDIENCE,
            'uid': uid,
            'iat': now,
            'exp': now + MAX_TOKEN_LIFETIME_SECONDS,
        }
        if tenant_id:
            payload['tenant_id'] = tenant_id

        if developer_claims is not None:
            payload['claims'] = developer_claims

        header = {'alg': signing_provider.alg}
        try:
            return jwt.encode(signing_provider.signer, payload, header=header)
        except google.auth.exceptions.TransportError as error:
            msg = 'Failed to sign custom token. {0}'.format(error)
            raise TokenSignError(msg, error)
Exemple #22
0
def test_id_token_jwt_grant():
    now = _helpers.utcnow()
    id_token_expiry = _helpers.datetime_to_secs(now)
    id_token = jwt.encode(SIGNER, {'exp': id_token_expiry}).decode('utf-8')
    request = make_request({'id_token': id_token, 'extra': 'data'})

    token, expiry, extra_data = _client.id_token_jwt_grant(
        request, 'http://example.com', 'assertion_value')

    # Check request call
    verify_request_params(request, {
        'grant_type': _client._JWT_GRANT_TYPE,
        'assertion': 'assertion_value'
    })

    # Check result
    assert token == id_token
    # JWT does not store microseconds
    now = now.replace(microsecond=0)
    assert expiry == now
    assert extra_data['extra'] == 'data'
def test_id_token_jwt_grant():
    now = _helpers.utcnow()
    id_token_expiry = _helpers.datetime_to_secs(now)
    id_token = jwt.encode(SIGNER, {"exp": id_token_expiry}).decode("utf-8")
    request = make_request({"id_token": id_token, "extra": "data"})

    token, expiry, extra_data = _client.id_token_jwt_grant(
        request, "http://example.com", "assertion_value")

    # Check request call
    verify_request_params(request, {
        "grant_type": _client._JWT_GRANT_TYPE,
        "assertion": "assertion_value"
    })

    # Check result
    assert token == id_token
    # JWT does not store microseconds
    now = now.replace(microsecond=0)
    assert expiry == now
    assert extra_data["extra"] == "data"
Exemple #24
0
	def _make_jwt_for_audience(self):
		"""
		Make a JSON Web Token given a service file

		:rtype: string
		:returns: signed authentication     

		"""     
		now = _helpers.utcnow()
		lifetime = timedelta(seconds=_TOKEN_EXPIRATION)
		self._token_expiration = now + lifetime

		payload = {
				'aud': self._token_uri,
				'iss': self._signer_email,
				'iat': _helpers.datetime_to_secs(now),
				'exp': _helpers.datetime_to_secs(self._token_expiration),
				'scope' : self._scopes 
		}

		return encode(self._signer, payload) # from google.auth.jwt.encode
Exemple #25
0
def generate_jwt(claims: Any,
                 google_application_credentials: Optional[Any] = None) -> Any:
    """Generates a signed JSON Web Token using a Google API Service Account."""

    if os.getenv("AUTH0_JWT_TOKEN"):
        return os.getenv("AUTH0_JWT_TOKEN")

    if not google_application_credentials:
        google_application_credentials = os.getenv(
            "GOOGLE_APPLICATION_CREDENTIALS")

    if not google_application_credentials:
        raise ValueError("Please provide GOOGLE_APPLICATION_CREDENTIALS")

    now = int(time.time())

    sa_email = Credentials.from_service_account_file(
        google_application_credentials).service_account_email

    payload = {
        "iat": now,
        "exp": now + 3600,
        # iss must match 'issuer' in the security configuration in your
        # swagger spec (e.g. service account email). It can be any string.
        "iss": sa_email,
        # aud must be either your Endpoints service name, or match the value
        # specified as the 'x-google-audience' in the OpenAPI document.
        "aud": audience,
        # sub and email should match the service account's email address
        "sub": sa_email,
        "email": sa_email,
    }

    claims.update(payload)

    signer = crypt.RSASigner.from_service_account_file(
        google_application_credentials)
    jwt_string = jwt.encode(signer, claims)

    return jwt_string
Exemple #26
0
def generate_jwt(service_account_file: str, client_email: str) -> str:
    """
    Generate service account JWT token

    :param service_account_file: Path to service account json file
    :param client_email: Service account email
    :return: JWT token
    """
    signer = google_auth_crypt.RSASigner.from_service_account_file(
        service_account_file)
    iat = time.time()
    exp = iat + 3600

    payload = {
        'iat': iat,
        'exp': exp,
        'iss': client_email,
        'target_audience':
        '563209362155-dmktm1rt2snprao3te1a5gf0tk9l39i8.apps.googleusercontent.com',
        'aud': "https://www.googleapis.com/oauth2/v4/token"
    }
    jwt = google_auth_jwt.encode(signer, payload)
    return jwt.decode('ascii')
Exemple #27
0
  def generateSignedJwt(self):
    jwtToSign = self.generateUnsignedJwt()
    signedJwt = jwtGoogle.encode(self.signer, jwtToSign)

    return signedJwt
    def _generate(self):
        _logger.info(
            "Attempting to generate access token from service account credentials in '%s'",
            self.credentials_filename)

        #
        # step #1 = read credentials from disk
        #
        try:
            assert self._credentials is None

            _logger.info(
                "attempting to read service account credentials from '%s'",
                self.credentials_filename)

            self._credentials = service_account.Credentials.from_service_account_file(self.credentials_filename)

            _logger.info(
                "successfully read service account credentials from '%s'",
                self.credentials_filename)

        except Exception as ex:
            _logger.error(
                "could not read service account credentials from '%s' - %s",
                self.credentials_filename,
                ex)

            self._credentials = None

            five_seconds = 5
            self._schedule_generation(five_seconds)

            return

        #
        # step #2 = build access token request
        #
        seconds_since_epoch = int(time.time())
        # :TODO: question = do we want to hardcode # seconds to expiry?
        one_hour_in_seconds = 60 * 60
        payload = {
            'iss': self._credentials.service_account_email,
            'scope': self.scope,
            'aud': 'https://www.googleapis.com/oauth2/v4/token',
            'exp': seconds_since_epoch + one_hour_in_seconds,
            'iat': seconds_since_epoch,
        }

        body_template = 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=%s'
        body = body_template % jwt.encode(self._credentials.signer, payload)

        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
        }

        #
        # the if statement below is :UGLY: but required given current istio limitations
        # described @ https://istio.io/docs/tasks/traffic-management/egress.html
        #
        if _using_istio():
            url = 'http://www.googleapis.com:443/oauth2/v4/token'
        else:
            url = 'https://www.googleapis.com/oauth2/v4/token'

        request = tornado.httpclient.HTTPRequest(
            url,
            method='POST',
            headers=tornado.httputil.HTTPHeaders(headers),
            body=body)
        http_client = tornado.httpclient.AsyncHTTPClient()
        http_client.fetch(
            request,
            callback=self._on_http_client_fetch_done)
Exemple #29
0
 def auth_header(self) -> dict:
     signer = RSASigner.from_service_account_file(
         self.service_account_auth_file)
     payload = {"email": self.service_account}
     jwt_token = jwt.encode(signer=signer, payload=payload).decode("ascii")
     return {"Authorization": f"Bearer {jwt_token}"}
Exemple #30
0
def test_encode_custom_alg_in_headers(signer):
    encoded = jwt.encode(signer, {}, header={"alg": "foo"})
    header = jwt.decode_header(encoded)
    assert header == {"typ": "JWT", "alg": "foo", "kid": signer.key_id}
def test_encode_basic(signer):
    test_payload = {"test": "value"}
    encoded = jwt.encode(signer, test_payload)
    header, payload, _, _ = jwt._unverified_decode(encoded)
    assert payload == test_payload
    assert header == {"typ": "JWT", "alg": "RS256", "kid": signer.key_id}
def test_decode_bad_token_no_iat_or_exp(signer):
    token = jwt.encode(signer, {'test': 'value'})
    with pytest.raises(ValueError) as excinfo:
        jwt.decode(token, PUBLIC_CERT_BYTES)
    assert excinfo.match(r'Token does not contain required claim')
Exemple #33
0
    service_account_info = json.load(fh)

signer = crypt.RSASigner.from_service_account_info(service_account_info)

now = int(time.time())
payload = {
    'iat': now,
    # expires after one hour.
    'exp': now + 3600,
    'iss': service_account_info['client_email'],
    # the URL of the target service.
    'target_audience': 'https://registry.endpoints.robco-166608.cloud.goog',
    # Google token endpoints URL, FIXME: use discovery doc
    'aud': 'https://www.googleapis.com/oauth2/v4/token'
}
signed_jwt = jwt.encode(signer, payload)

pprint(signed_jwt)

# send the JWT to Google Token endpoints to request Google ID token

params = {
    'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion': signed_jwt
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post('https://www.googleapis.com/oauth2/v4/token',
                         data=params,
                         headers=headers)
res = response.json()
def test_encode_basic(signer):
    test_payload = {'test': 'value'}
    encoded = jwt.encode(signer, test_payload)
    header, payload, _, _ = jwt._unverified_decode(encoded)
    assert payload == test_payload
    assert header == {'typ': 'JWT', 'alg': 'RS256', 'kid': signer.key_id}