Skip to content

Commit fadfc4b

Browse files
Niloth-ptheofficialvedantjoshi
authored andcommitted
google-calendar: Support manual authorization using auth code.
This allows the integration to be run from non-interactive environments or on devices without browsers, like remote servers. Co-authored-by: Vedant Joshi <[email protected]>
1 parent e7fa631 commit fadfc4b

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

zulip/integrations/google/get-google-credentials

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ CLIENT_SECRET_FILE = "client_secret.json" # noqa: S105
1515
HOME_DIR = os.path.expanduser("~")
1616

1717

18-
def get_credentials(tokens_path: str, scopes: List[str]) -> Credentials:
18+
def get_credentials(
19+
tokens_path: str, scopes: List[str], noauth_local_webserver: bool = False
20+
) -> Credentials:
1921
"""
2022
Writes google tokens to a json file, using the client secret file (for the OAuth flow),
2123
and the refresh token.
@@ -27,6 +29,8 @@ def get_credentials(tokens_path: str, scopes: List[str]) -> Credentials:
2729
2830
The OAuth2 flow needs the client secret file, and requires the user to grant access to
2931
the application via a browser authorization page, for the first run.
32+
The authorization can be done either automatically using a local web server,
33+
or manually by copy-pasting the auth code from the browser into the command line.
3034
3135
The fetched tokens are written to storage in a json file, for reference by other scripts.
3236
"""
@@ -44,8 +48,21 @@ def get_credentials(tokens_path: str, scopes: List[str]) -> Credentials:
4448
client_secret_path,
4549
)
4650
sys.exit(1)
47-
flow = InstalledAppFlow.from_client_secrets_file(client_secret_path, scopes)
48-
creds = flow.run_local_server(port=0)
51+
flow = InstalledAppFlow.from_client_secrets_file(
52+
client_secret_path,
53+
scopes,
54+
redirect_uri="urn:ietf:wg:oauth:2.0:oob" if noauth_local_webserver else None,
55+
)
56+
57+
if noauth_local_webserver:
58+
auth_url, _ = flow.authorization_url(access_type="offline")
59+
auth_code = input(
60+
f"Please visit this URL to authorize this application:\n{auth_url}\nEnter the authorization code: "
61+
)
62+
flow.fetch_token(code=auth_code)
63+
creds = flow.credentials
64+
else:
65+
creds = flow.run_local_server(port=0)
4966
with open(tokens_path, "w") as token:
5067
token.write(creds.to_json())
5168
return creds

zulip/integrations/google/google-calendar

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ sys.path.append(os.path.dirname(__file__))
3232
usage = r"""google-calendar [--config-file PATH_TO_ZULIPRC_OF_BOT]
3333
[--interval MINUTES] [--calendar CALENDAR_ID]
3434
[--channel CHANNEL_NAME] [--topic TOPIC_NAME]
35+
[-n] [--noauth_local_webserver]
3536
3637
This integration can be used to send Zulip messages as reminders for upcoming events from your Google Calendar.
3738
@@ -62,6 +63,13 @@ parser.add_argument(
6263
help="The topic to which to send the reminders to. Ignored if --channel is unspecified. 'calendar-reminders' is used as the default topic name.",
6364
default="calendar-reminders",
6465
)
66+
parser.add_argument(
67+
"-n",
68+
"--noauth_local_webserver",
69+
action="store_true",
70+
default=False,
71+
help="The default authorization process runs a local web server, which requires a browser on the same machine. For non-interactive environments and machines without browser access, e.g., remote servers, this option allows manual authorization. The authorization URL is printed, which the user can copy into a browser, copy the resulting authorization code, and paste back into the command line.",
72+
)
6573
options = parser.parse_args()
6674

6775
zulip_client = zulip.init_from_options(options)
@@ -91,7 +99,7 @@ def get_credentials() -> Credentials:
9199
try:
92100
tokens_path = os.path.join(HOME_DIR, TOKENS_FILE)
93101
fetch_creds = runpy.run_path("./get-google-credentials")["get_credentials"]
94-
return fetch_creds(tokens_path, SCOPES)
102+
return fetch_creds(tokens_path, SCOPES, options.noauth_local_webserver)
95103
except Exception:
96104
logging.exception("Error getting google credentials")
97105
sys.exit(1)

0 commit comments

Comments
 (0)