We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
KFP 0.2.1 SDK client broken when inverse proxy host is used
This bug is introduced in #2896 

Under the hood `subprocess.check_output()` return bytes instead of string. However in `kfp_server_api/configuration.py` it was assumed to be string, which caused error like the following:

```
~/.local/lib/python3.5/site-packages/kfp_server_api/configuration.py in get_api_key_with_prefix(self, identifier)
    203         if (self.api_key.get(identifier) and
    204                 self.api_key_prefix.get(identifier)):
--> 205             return self.api_key_prefix[identifier] + ' ' + self.api_key[identifier]  # noqa: E501
    206         elif self.api_key.get(identifier):
    207             return self.api_key[identifier]

TypeError: Can't convert 'bytes' object to str implicitly
```
This impacts some CUJs involving TFX CLI and CAIP notebook experiences. Will send out a fix today.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sdk/python/kfp/_auth.py`
Content:
```
1 # Copyright 2018 Google LLC
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import logging
16 import os
17 import subprocess
18 import google.auth
19 import google.auth.app_engine
20 import google.auth.compute_engine.credentials
21 import google.auth.iam
22 from google.auth.transport.requests import Request
23 import google.oauth2.credentials
24 import google.oauth2.service_account
25 import requests_toolbelt.adapters.appengine
26 from webbrowser import open_new_tab
27 import requests
28 import json
29 
30 IAM_SCOPE = 'https://www.googleapis.com/auth/iam'
31 OAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'
32 LOCAL_KFP_CREDENTIAL = os.path.expanduser('~/.config/kfp/credentials.json')
33 
34 def get_gcp_access_token():
35     """Get and return GCP access token for the current Application Default
36     Credentials. If not set, returns None. For more information, see
37     https://cloud.google.com/sdk/gcloud/reference/auth/application-default/print-access-token
38     """
39     args = ['gcloud', 'auth', 'print-access-token']
40     return subprocess.check_output(args).rstrip()
41 
42 def get_auth_token(client_id, other_client_id, other_client_secret):
43     """Gets auth token from default service account or user account."""
44     if os.path.exists(LOCAL_KFP_CREDENTIAL):
45         # fetch IAP auth token using the locally stored credentials.
46         with open(LOCAL_KFP_CREDENTIAL, 'r') as f:
47             credentials = json.load(f)
48         if client_id in credentials:
49             return id_token_from_refresh_token(credentials[client_id]['other_client_id'],
50                                                credentials[client_id]['other_client_secret'],
51                                                credentials[client_id]['refresh_token'],
52                                                client_id)
53     if other_client_id is None or other_client_secret is None:
54         # fetch IAP auth token: service accounts
55         token = get_auth_token_from_sa(client_id)
56     else:
57         # fetch IAP auth token: user account
58         # Obtain the ID token for provided Client ID with user accounts.
59         #  Flow: get authorization code -> exchange for refresh token -> obtain and return ID token
60         refresh_token = get_refresh_token_from_client_id(other_client_id, other_client_secret)
61         credentials = {}
62         if os.path.exists(LOCAL_KFP_CREDENTIAL):
63             with open(LOCAL_KFP_CREDENTIAL, 'r') as f:
64                 credentials = json.load(f)
65         credentials[client_id] = {}
66         credentials[client_id]['other_client_id'] = other_client_id
67         credentials[client_id]['other_client_secret'] = other_client_secret
68         credentials[client_id]['refresh_token'] = refresh_token
69         #TODO: handle the case when the refresh_token expires.
70         #   which only happens if the refresh_token is not used once for six months.
71         if not os.path.exists(os.path.dirname(LOCAL_KFP_CREDENTIAL)):
72             os.makedirs(os.path.dirname(LOCAL_KFP_CREDENTIAL))
73         with open(LOCAL_KFP_CREDENTIAL, 'w') as f:
74             json.dump(credentials, f)
75         token = id_token_from_refresh_token(other_client_id, other_client_secret, refresh_token, client_id)
76     return token
77 
78 def get_auth_token_from_sa(client_id):
79     """Gets auth token from default service account.
80 
81     If no service account credential is found, returns None.
82     """
83     service_account_credentials = get_service_account_credentials(client_id)
84     if service_account_credentials:
85         return get_google_open_id_connect_token(service_account_credentials)
86     return None
87 
88 def get_service_account_credentials(client_id):
89     # Figure out what environment we're running in and get some preliminary
90     # information about the service account.
91     bootstrap_credentials, _ = google.auth.default(
92         scopes=[IAM_SCOPE])
93     if isinstance(bootstrap_credentials,
94                   google.oauth2.credentials.Credentials):
95         logging.info('Found OAuth2 credentials and skip SA auth.')
96         return None
97     elif isinstance(bootstrap_credentials,
98                     google.auth.app_engine.Credentials):
99         requests_toolbelt.adapters.appengine.monkeypatch()
100 
101     # For service account's using the Compute Engine metadata service,
102     # service_account_email isn't available until refresh is called.
103     bootstrap_credentials.refresh(Request())
104     signer_email = bootstrap_credentials.service_account_email
105     if isinstance(bootstrap_credentials,
106                   google.auth.compute_engine.credentials.Credentials):
107         # Since the Compute Engine metadata service doesn't expose the service
108         # account key, we use the IAM signBlob API to sign instead.
109         # In order for this to work:
110         #
111         # 1. Your VM needs the https://www.googleapis.com/auth/iam scope.
112         #    You can specify this specific scope when creating a VM
113         #    through the API or gcloud. When using Cloud Console,
114         #    you'll need to specify the "full access to all Cloud APIs"
115         #    scope. A VM's scopes can only be specified at creation time.
116         #
117         # 2. The VM's default service account needs the "Service Account Actor"
118         #    role. This can be found under the "Project" category in Cloud
119         #    Console, or roles/iam.serviceAccountActor in gcloud.
120         signer = google.auth.iam.Signer(
121             Request(), bootstrap_credentials, signer_email)
122     else:
123         # A Signer object can sign a JWT using the service account's key.
124         signer = bootstrap_credentials.signer
125 
126     # Construct OAuth 2.0 service account credentials using the signer
127     # and email acquired from the bootstrap credentials.
128     return google.oauth2.service_account.Credentials(
129         signer, signer_email, token_uri=OAUTH_TOKEN_URI, additional_claims={
130             'target_audience': client_id
131         })
132 
133 def get_google_open_id_connect_token(service_account_credentials):
134     """Get an OpenID Connect token issued by Google for the service account.
135     This function:
136       1. Generates a JWT signed with the service account's private key
137          containing a special "target_audience" claim.
138       2. Sends it to the OAUTH_TOKEN_URI endpoint. Because the JWT in #1
139          has a target_audience claim, that endpoint will respond with
140          an OpenID Connect token for the service account -- in other words,
141          a JWT signed by *Google*. The aud claim in this JWT will be
142          set to the value from the target_audience claim in #1.
143     For more information, see
144     https://developers.google.com/identity/protocols/OAuth2ServiceAccount .
145     The HTTP/REST example on that page describes the JWT structure and
146     demonstrates how to call the token endpoint. (The example on that page
147     shows how to get an OAuth2 access token; this code is using a
148     modified version of it to get an OpenID Connect token.)
149     """
150 
151     service_account_jwt = (
152         service_account_credentials._make_authorization_grant_assertion())
153     request = google.auth.transport.requests.Request()
154     body = {
155         'assertion': service_account_jwt,
156         'grant_type': google.oauth2._client._JWT_GRANT_TYPE,
157     }
158     token_response = google.oauth2._client._token_endpoint_request(
159         request, OAUTH_TOKEN_URI, body)
160     return token_response['id_token']
161 
162 def get_refresh_token_from_client_id(client_id, client_secret):
163     """Obtain the ID token for provided Client ID with user accounts.
164         Flow: get authorization code -> exchange for refresh token -> obtain and return ID token
165     """
166     auth_code = get_auth_code(client_id)
167     return get_refresh_token_from_code(auth_code, client_id, client_secret)
168 
169 def get_auth_code(client_id):
170     auth_url = "https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&response_type=code&scope=openid%%20email&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob"%client_id
171     print(auth_url)
172     open_new_tab(auth_url)
173     return input("Authorization code: ")
174 
175 def get_refresh_token_from_code(auth_code, client_id, client_secret):
176     payload = {"code": auth_code, "client_id": client_id, "client_secret": client_secret,
177                "redirect_uri": "urn:ietf:wg:oauth:2.0:oob", "grant_type": "authorization_code"}
178     res = requests.post(OAUTH_TOKEN_URI, data=payload)
179     return (str(json.loads(res.text)[u"refresh_token"]))
180 
181 def id_token_from_refresh_token(client_id, client_secret, refresh_token, audience):
182     payload = {"client_id": client_id, "client_secret": client_secret,
183                "refresh_token": refresh_token, "grant_type": "refresh_token",
184                "audience": audience}
185     res = requests.post(OAUTH_TOKEN_URI, data=payload)
186     return (str(json.loads(res.text)[u"id_token"]))
187
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sdk/python/kfp/_auth.py b/sdk/python/kfp/_auth.py
--- a/sdk/python/kfp/_auth.py
+++ b/sdk/python/kfp/_auth.py
@@ -37,7 +37,8 @@
     https://cloud.google.com/sdk/gcloud/reference/auth/application-default/print-access-token
     """
     args = ['gcloud', 'auth', 'print-access-token']
-    return subprocess.check_output(args).rstrip()
+    # Casting to string to accommodate API server request schema.
+    return subprocess.check_output(args).rstrip().decode("utf-8")
 
 def get_auth_token(client_id, other_client_id, other_client_secret):
     """Gets auth token from default service account or user account."""

{"golden_diff": "diff --git a/sdk/python/kfp/_auth.py b/sdk/python/kfp/_auth.py\n--- a/sdk/python/kfp/_auth.py\n+++ b/sdk/python/kfp/_auth.py\n@@ -37,7 +37,8 @@\n     https://cloud.google.com/sdk/gcloud/reference/auth/application-default/print-access-token\n     \"\"\"\n     args = ['gcloud', 'auth', 'print-access-token']\n-    return subprocess.check_output(args).rstrip()\n+    # Casting to string to accommodate API server request schema.\n+    return subprocess.check_output(args).rstrip().decode(\"utf-8\")\n \n def get_auth_token(client_id, other_client_id, other_client_secret):\n     \"\"\"Gets auth token from default service account or user account.\"\"\"\n", "issue": "KFP 0.2.1 SDK client broken when inverse proxy host is used\nThis bug is introduced in #2896 \r\n\r\nUnder the hood `subprocess.check_output()` return bytes instead of string. However in `kfp_server_api/configuration.py` it was assumed to be string, which caused error like the following:\r\n\r\n```\r\n~/.local/lib/python3.5/site-packages/kfp_server_api/configuration.py in get_api_key_with_prefix(self, identifier)\r\n    203         if (self.api_key.get(identifier) and\r\n    204                 self.api_key_prefix.get(identifier)):\r\n--> 205             return self.api_key_prefix[identifier] + ' ' + self.api_key[identifier]  # noqa: E501\r\n    206         elif self.api_key.get(identifier):\r\n    207             return self.api_key[identifier]\r\n\r\nTypeError: Can't convert 'bytes' object to str implicitly\r\n```\r\nThis impacts some CUJs involving TFX CLI and CAIP notebook experiences. Will send out a fix today.\r\n\r\n\n", "before_files": [{"content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport logging\nimport os\nimport subprocess\nimport google.auth\nimport google.auth.app_engine\nimport google.auth.compute_engine.credentials\nimport google.auth.iam\nfrom google.auth.transport.requests import Request\nimport google.oauth2.credentials\nimport google.oauth2.service_account\nimport requests_toolbelt.adapters.appengine\nfrom webbrowser import open_new_tab\nimport requests\nimport json\n\nIAM_SCOPE = 'https://www.googleapis.com/auth/iam'\nOAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'\nLOCAL_KFP_CREDENTIAL = os.path.expanduser('~/.config/kfp/credentials.json')\n\ndef get_gcp_access_token():\n    \"\"\"Get and return GCP access token for the current Application Default\n    Credentials. If not set, returns None. For more information, see\n    https://cloud.google.com/sdk/gcloud/reference/auth/application-default/print-access-token\n    \"\"\"\n    args = ['gcloud', 'auth', 'print-access-token']\n    return subprocess.check_output(args).rstrip()\n\ndef get_auth_token(client_id, other_client_id, other_client_secret):\n    \"\"\"Gets auth token from default service account or user account.\"\"\"\n    if os.path.exists(LOCAL_KFP_CREDENTIAL):\n        # fetch IAP auth token using the locally stored credentials.\n        with open(LOCAL_KFP_CREDENTIAL, 'r') as f:\n            credentials = json.load(f)\n        if client_id in credentials:\n            return id_token_from_refresh_token(credentials[client_id]['other_client_id'],\n                                               credentials[client_id]['other_client_secret'],\n                                               credentials[client_id]['refresh_token'],\n                                               client_id)\n    if other_client_id is None or other_client_secret is None:\n        # fetch IAP auth token: service accounts\n        token = get_auth_token_from_sa(client_id)\n    else:\n        # fetch IAP auth token: user account\n        # Obtain the ID token for provided Client ID with user accounts.\n        #  Flow: get authorization code -> exchange for refresh token -> obtain and return ID token\n        refresh_token = get_refresh_token_from_client_id(other_client_id, other_client_secret)\n        credentials = {}\n        if os.path.exists(LOCAL_KFP_CREDENTIAL):\n            with open(LOCAL_KFP_CREDENTIAL, 'r') as f:\n                credentials = json.load(f)\n        credentials[client_id] = {}\n        credentials[client_id]['other_client_id'] = other_client_id\n        credentials[client_id]['other_client_secret'] = other_client_secret\n        credentials[client_id]['refresh_token'] = refresh_token\n        #TODO: handle the case when the refresh_token expires.\n        #   which only happens if the refresh_token is not used once for six months.\n        if not os.path.exists(os.path.dirname(LOCAL_KFP_CREDENTIAL)):\n            os.makedirs(os.path.dirname(LOCAL_KFP_CREDENTIAL))\n        with open(LOCAL_KFP_CREDENTIAL, 'w') as f:\n            json.dump(credentials, f)\n        token = id_token_from_refresh_token(other_client_id, other_client_secret, refresh_token, client_id)\n    return token\n\ndef get_auth_token_from_sa(client_id):\n    \"\"\"Gets auth token from default service account.\n\n    If no service account credential is found, returns None.\n    \"\"\"\n    service_account_credentials = get_service_account_credentials(client_id)\n    if service_account_credentials:\n        return get_google_open_id_connect_token(service_account_credentials)\n    return None\n\ndef get_service_account_credentials(client_id):\n    # Figure out what environment we're running in and get some preliminary\n    # information about the service account.\n    bootstrap_credentials, _ = google.auth.default(\n        scopes=[IAM_SCOPE])\n    if isinstance(bootstrap_credentials,\n                  google.oauth2.credentials.Credentials):\n        logging.info('Found OAuth2 credentials and skip SA auth.')\n        return None\n    elif isinstance(bootstrap_credentials,\n                    google.auth.app_engine.Credentials):\n        requests_toolbelt.adapters.appengine.monkeypatch()\n\n    # For service account's using the Compute Engine metadata service,\n    # service_account_email isn't available until refresh is called.\n    bootstrap_credentials.refresh(Request())\n    signer_email = bootstrap_credentials.service_account_email\n    if isinstance(bootstrap_credentials,\n                  google.auth.compute_engine.credentials.Credentials):\n        # Since the Compute Engine metadata service doesn't expose the service\n        # account key, we use the IAM signBlob API to sign instead.\n        # In order for this to work:\n        #\n        # 1. Your VM needs the https://www.googleapis.com/auth/iam scope.\n        #    You can specify this specific scope when creating a VM\n        #    through the API or gcloud. When using Cloud Console,\n        #    you'll need to specify the \"full access to all Cloud APIs\"\n        #    scope. A VM's scopes can only be specified at creation time.\n        #\n        # 2. The VM's default service account needs the \"Service Account Actor\"\n        #    role. This can be found under the \"Project\" category in Cloud\n        #    Console, or roles/iam.serviceAccountActor in gcloud.\n        signer = google.auth.iam.Signer(\n            Request(), bootstrap_credentials, signer_email)\n    else:\n        # A Signer object can sign a JWT using the service account's key.\n        signer = bootstrap_credentials.signer\n\n    # Construct OAuth 2.0 service account credentials using the signer\n    # and email acquired from the bootstrap credentials.\n    return google.oauth2.service_account.Credentials(\n        signer, signer_email, token_uri=OAUTH_TOKEN_URI, additional_claims={\n            'target_audience': client_id\n        })\n\ndef get_google_open_id_connect_token(service_account_credentials):\n    \"\"\"Get an OpenID Connect token issued by Google for the service account.\n    This function:\n      1. Generates a JWT signed with the service account's private key\n         containing a special \"target_audience\" claim.\n      2. Sends it to the OAUTH_TOKEN_URI endpoint. Because the JWT in #1\n         has a target_audience claim, that endpoint will respond with\n         an OpenID Connect token for the service account -- in other words,\n         a JWT signed by *Google*. The aud claim in this JWT will be\n         set to the value from the target_audience claim in #1.\n    For more information, see\n    https://developers.google.com/identity/protocols/OAuth2ServiceAccount .\n    The HTTP/REST example on that page describes the JWT structure and\n    demonstrates how to call the token endpoint. (The example on that page\n    shows how to get an OAuth2 access token; this code is using a\n    modified version of it to get an OpenID Connect token.)\n    \"\"\"\n\n    service_account_jwt = (\n        service_account_credentials._make_authorization_grant_assertion())\n    request = google.auth.transport.requests.Request()\n    body = {\n        'assertion': service_account_jwt,\n        'grant_type': google.oauth2._client._JWT_GRANT_TYPE,\n    }\n    token_response = google.oauth2._client._token_endpoint_request(\n        request, OAUTH_TOKEN_URI, body)\n    return token_response['id_token']\n\ndef get_refresh_token_from_client_id(client_id, client_secret):\n    \"\"\"Obtain the ID token for provided Client ID with user accounts.\n        Flow: get authorization code -> exchange for refresh token -> obtain and return ID token\n    \"\"\"\n    auth_code = get_auth_code(client_id)\n    return get_refresh_token_from_code(auth_code, client_id, client_secret)\n\ndef get_auth_code(client_id):\n    auth_url = \"https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&response_type=code&scope=openid%%20email&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob\"%client_id\n    print(auth_url)\n    open_new_tab(auth_url)\n    return input(\"Authorization code: \")\n\ndef get_refresh_token_from_code(auth_code, client_id, client_secret):\n    payload = {\"code\": auth_code, \"client_id\": client_id, \"client_secret\": client_secret,\n               \"redirect_uri\": \"urn:ietf:wg:oauth:2.0:oob\", \"grant_type\": \"authorization_code\"}\n    res = requests.post(OAUTH_TOKEN_URI, data=payload)\n    return (str(json.loads(res.text)[u\"refresh_token\"]))\n\ndef id_token_from_refresh_token(client_id, client_secret, refresh_token, audience):\n    payload = {\"client_id\": client_id, \"client_secret\": client_secret,\n               \"refresh_token\": refresh_token, \"grant_type\": \"refresh_token\",\n               \"audience\": audience}\n    res = requests.post(OAUTH_TOKEN_URI, data=payload)\n    return (str(json.loads(res.text)[u\"id_token\"]))\n", "path": "sdk/python/kfp/_auth.py"}], "after_files": [{"content": "# Copyright 2018 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport logging\nimport os\nimport subprocess\nimport google.auth\nimport google.auth.app_engine\nimport google.auth.compute_engine.credentials\nimport google.auth.iam\nfrom google.auth.transport.requests import Request\nimport google.oauth2.credentials\nimport google.oauth2.service_account\nimport requests_toolbelt.adapters.appengine\nfrom webbrowser import open_new_tab\nimport requests\nimport json\n\nIAM_SCOPE = 'https://www.googleapis.com/auth/iam'\nOAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'\nLOCAL_KFP_CREDENTIAL = os.path.expanduser('~/.config/kfp/credentials.json')\n\ndef get_gcp_access_token():\n    \"\"\"Get and return GCP access token for the current Application Default\n    Credentials. If not set, returns None. For more information, see\n    https://cloud.google.com/sdk/gcloud/reference/auth/application-default/print-access-token\n    \"\"\"\n    args = ['gcloud', 'auth', 'print-access-token']\n    # Casting to string to accommodate API server request schema.\n    return subprocess.check_output(args).rstrip().decode(\"utf-8\")\n\ndef get_auth_token(client_id, other_client_id, other_client_secret):\n    \"\"\"Gets auth token from default service account or user account.\"\"\"\n    if os.path.exists(LOCAL_KFP_CREDENTIAL):\n        # fetch IAP auth token using the locally stored credentials.\n        with open(LOCAL_KFP_CREDENTIAL, 'r') as f:\n            credentials = json.load(f)\n        if client_id in credentials:\n            return id_token_from_refresh_token(credentials[client_id]['other_client_id'],\n                                               credentials[client_id]['other_client_secret'],\n                                               credentials[client_id]['refresh_token'],\n                                               client_id)\n    if other_client_id is None or other_client_secret is None:\n        # fetch IAP auth token: service accounts\n        token = get_auth_token_from_sa(client_id)\n    else:\n        # fetch IAP auth token: user account\n        # Obtain the ID token for provided Client ID with user accounts.\n        #  Flow: get authorization code -> exchange for refresh token -> obtain and return ID token\n        refresh_token = get_refresh_token_from_client_id(other_client_id, other_client_secret)\n        credentials = {}\n        if os.path.exists(LOCAL_KFP_CREDENTIAL):\n            with open(LOCAL_KFP_CREDENTIAL, 'r') as f:\n                credentials = json.load(f)\n        credentials[client_id] = {}\n        credentials[client_id]['other_client_id'] = other_client_id\n        credentials[client_id]['other_client_secret'] = other_client_secret\n        credentials[client_id]['refresh_token'] = refresh_token\n        #TODO: handle the case when the refresh_token expires.\n        #   which only happens if the refresh_token is not used once for six months.\n        if not os.path.exists(os.path.dirname(LOCAL_KFP_CREDENTIAL)):\n            os.makedirs(os.path.dirname(LOCAL_KFP_CREDENTIAL))\n        with open(LOCAL_KFP_CREDENTIAL, 'w') as f:\n            json.dump(credentials, f)\n        token = id_token_from_refresh_token(other_client_id, other_client_secret, refresh_token, client_id)\n    return token\n\ndef get_auth_token_from_sa(client_id):\n    \"\"\"Gets auth token from default service account.\n\n    If no service account credential is found, returns None.\n    \"\"\"\n    service_account_credentials = get_service_account_credentials(client_id)\n    if service_account_credentials:\n        return get_google_open_id_connect_token(service_account_credentials)\n    return None\n\ndef get_service_account_credentials(client_id):\n    # Figure out what environment we're running in and get some preliminary\n    # information about the service account.\n    bootstrap_credentials, _ = google.auth.default(\n        scopes=[IAM_SCOPE])\n    if isinstance(bootstrap_credentials,\n                  google.oauth2.credentials.Credentials):\n        logging.info('Found OAuth2 credentials and skip SA auth.')\n        return None\n    elif isinstance(bootstrap_credentials,\n                    google.auth.app_engine.Credentials):\n        requests_toolbelt.adapters.appengine.monkeypatch()\n\n    # For service account's using the Compute Engine metadata service,\n    # service_account_email isn't available until refresh is called.\n    bootstrap_credentials.refresh(Request())\n    signer_email = bootstrap_credentials.service_account_email\n    if isinstance(bootstrap_credentials,\n                  google.auth.compute_engine.credentials.Credentials):\n        # Since the Compute Engine metadata service doesn't expose the service\n        # account key, we use the IAM signBlob API to sign instead.\n        # In order for this to work:\n        #\n        # 1. Your VM needs the https://www.googleapis.com/auth/iam scope.\n        #    You can specify this specific scope when creating a VM\n        #    through the API or gcloud. When using Cloud Console,\n        #    you'll need to specify the \"full access to all Cloud APIs\"\n        #    scope. A VM's scopes can only be specified at creation time.\n        #\n        # 2. The VM's default service account needs the \"Service Account Actor\"\n        #    role. This can be found under the \"Project\" category in Cloud\n        #    Console, or roles/iam.serviceAccountActor in gcloud.\n        signer = google.auth.iam.Signer(\n            Request(), bootstrap_credentials, signer_email)\n    else:\n        # A Signer object can sign a JWT using the service account's key.\n        signer = bootstrap_credentials.signer\n\n    # Construct OAuth 2.0 service account credentials using the signer\n    # and email acquired from the bootstrap credentials.\n    return google.oauth2.service_account.Credentials(\n        signer, signer_email, token_uri=OAUTH_TOKEN_URI, additional_claims={\n            'target_audience': client_id\n        })\n\ndef get_google_open_id_connect_token(service_account_credentials):\n    \"\"\"Get an OpenID Connect token issued by Google for the service account.\n    This function:\n      1. Generates a JWT signed with the service account's private key\n         containing a special \"target_audience\" claim.\n      2. Sends it to the OAUTH_TOKEN_URI endpoint. Because the JWT in #1\n         has a target_audience claim, that endpoint will respond with\n         an OpenID Connect token for the service account -- in other words,\n         a JWT signed by *Google*. The aud claim in this JWT will be\n         set to the value from the target_audience claim in #1.\n    For more information, see\n    https://developers.google.com/identity/protocols/OAuth2ServiceAccount .\n    The HTTP/REST example on that page describes the JWT structure and\n    demonstrates how to call the token endpoint. (The example on that page\n    shows how to get an OAuth2 access token; this code is using a\n    modified version of it to get an OpenID Connect token.)\n    \"\"\"\n\n    service_account_jwt = (\n        service_account_credentials._make_authorization_grant_assertion())\n    request = google.auth.transport.requests.Request()\n    body = {\n        'assertion': service_account_jwt,\n        'grant_type': google.oauth2._client._JWT_GRANT_TYPE,\n    }\n    token_response = google.oauth2._client._token_endpoint_request(\n        request, OAUTH_TOKEN_URI, body)\n    return token_response['id_token']\n\ndef get_refresh_token_from_client_id(client_id, client_secret):\n    \"\"\"Obtain the ID token for provided Client ID with user accounts.\n        Flow: get authorization code -> exchange for refresh token -> obtain and return ID token\n    \"\"\"\n    auth_code = get_auth_code(client_id)\n    return get_refresh_token_from_code(auth_code, client_id, client_secret)\n\ndef get_auth_code(client_id):\n    auth_url = \"https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&response_type=code&scope=openid%%20email&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob\"%client_id\n    print(auth_url)\n    open_new_tab(auth_url)\n    return input(\"Authorization code: \")\n\ndef get_refresh_token_from_code(auth_code, client_id, client_secret):\n    payload = {\"code\": auth_code, \"client_id\": client_id, \"client_secret\": client_secret,\n               \"redirect_uri\": \"urn:ietf:wg:oauth:2.0:oob\", \"grant_type\": \"authorization_code\"}\n    res = requests.post(OAUTH_TOKEN_URI, data=payload)\n    return (str(json.loads(res.text)[u\"refresh_token\"]))\n\ndef id_token_from_refresh_token(client_id, client_secret, refresh_token, audience):\n    payload = {\"client_id\": client_id, \"client_secret\": client_secret,\n               \"refresh_token\": refresh_token, \"grant_type\": \"refresh_token\",\n               \"audience\": audience}\n    res = requests.post(OAUTH_TOKEN_URI, data=payload)\n    return (str(json.loads(res.text)[u\"id_token\"]))\n", "path": "sdk/python/kfp/_auth.py"}]}