We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add clear instructions for authorization code / token
I was following [this official example](https://colab.research.google.com/github/kubeflow/website/blob/master/content/en/docs/pipelines/sdk/python-function-components.ipynb) to submit a pipeline via Jupyter or Python script

I filled in the client id and credentials [following these instructions](https://www.kubeflow.org/docs/gke/pipelines/authentication-sdk/#connecting-to-kubeflow-pipelines-in-a-full-kubeflow-deployment), but when I try to [compile the pipeline](https://www.kubeflow.org/docs/pipelines/sdk/build-component/#compile-the-pipeline) with
```
dsl-compile --py [path/to/python/file] --output [path/to/output/tar.gz]
```
The resulting prompt doesn't make it evident that the url can be copy pasted into the browser, to get the Authorization code, and I got stuck on it for a while. Looking back it's kind of an Occam's razor thing, but it could have saved a lot of time with even simple instructions "copy paste this url"

![Screen Shot 2021-01-12 at 5 46 15 PM copy](https://user-images.githubusercontent.com/23287722/104479213-2982f800-5591-11eb-81ca-e2cf4df92b4f.png)



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

{"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@@ -178,7 +178,7 @@\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+    return input(\"If there's no browser window prompt, please direct to the URL above, then copy and paste the authorization code here: \")\n \n def 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", "issue": "Add clear instructions for authorization code / token\nI was following [this official example](https://colab.research.google.com/github/kubeflow/website/blob/master/content/en/docs/pipelines/sdk/python-function-components.ipynb) to submit a pipeline via Jupyter or Python script\r\n\r\nI filled in the client id and credentials [following these instructions](https://www.kubeflow.org/docs/gke/pipelines/authentication-sdk/#connecting-to-kubeflow-pipelines-in-a-full-kubeflow-deployment), but when I try to [compile the pipeline](https://www.kubeflow.org/docs/pipelines/sdk/build-component/#compile-the-pipeline) with\r\n```\r\ndsl-compile --py [path/to/python/file] --output [path/to/output/tar.gz]\r\n```\r\nThe resulting prompt doesn't make it evident that the url can be copy pasted into the browser, to get the Authorization code, and I got stuck on it for a while. Looking back it's kind of an Occam's razor thing, but it could have saved a lot of time with even simple instructions \"copy paste this url\"\r\n\r\n![Screen Shot 2021-01-12 at 5 46 15 PM copy](https://user-images.githubusercontent.com/23287722/104479213-2982f800-5591-11eb-81ca-e2cf4df92b4f.png)\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 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    token = None\n    try:\n        creds, project = google.auth.default(scopes=[\"https://www.googleapis.com/auth/cloud-platform\"])\n        if not creds.valid:\n            auth_req = Request()\n            creds.refresh(auth_req)\n        if creds.valid:\n            token = creds.token\n    except Exception as e:\n      logging.warning('Failed to get GCP access token: %s', e)\n    return token\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 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    token = None\n    try:\n        creds, project = google.auth.default(scopes=[\"https://www.googleapis.com/auth/cloud-platform\"])\n        if not creds.valid:\n            auth_req = Request()\n            creds.refresh(auth_req)\n        if creds.valid:\n            token = creds.token\n    except Exception as e:\n      logging.warning('Failed to get GCP access token: %s', e)\n    return token\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(\"If there's no browser window prompt, please direct to the URL above, then copy and paste the authorization code here: \")\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"}]}