oauth2-cli-auth 1.2.0__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/PKG-INFO +2 -1
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/oauth2_cli_auth/_timeout.py +1 -1
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/oauth2_cli_auth/_urllib_util.py +2 -1
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/oauth2_cli_auth/code_grant.py +38 -10
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/oauth2_cli_auth/http_server.py +1 -1
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/pyproject.toml +2 -3
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/LICENSE +0 -0
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/README.md +0 -0
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/oauth2_cli_auth/__init__.py +0 -0
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/oauth2_cli_auth/conftest.py +0 -0
- {oauth2_cli_auth-1.2.0 → oauth2_cli_auth-1.3.0}/oauth2_cli_auth/simplified_flow.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: oauth2-cli-auth
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Authenticate against OAuth2 Provider in Python CLIs
|
|
5
5
|
Home-page: https://github.com/timo-reymann/python-oauth2-cli-auth
|
|
6
6
|
License: MIT
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
23
|
Project-URL: Bug Tracker, https://github.com/timo-reymann/python-oauth2-cli-auth/issues
|
|
23
24
|
Project-URL: Repository, https://github.com/timo-reymann/python-oauth2-cli-auth
|
|
24
25
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import time
|
|
3
3
|
import urllib
|
|
4
|
+
from urllib.error import URLError
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def _urlopen_with_backoff(url, max_retries=3, base_delay=1, timeout=15):
|
|
@@ -15,7 +16,7 @@ def _urlopen_with_backoff(url, max_retries=3, base_delay=1, timeout=15):
|
|
|
15
16
|
delay = base_delay * (2 ** retries)
|
|
16
17
|
time.sleep(delay)
|
|
17
18
|
|
|
18
|
-
raise
|
|
19
|
+
raise URLError(f"Failed to open URL after {max_retries} retries")
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _load_json(url_or_request: str | urllib.request.Request) -> dict:
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import urllib.parse
|
|
3
|
+
import urllib.request
|
|
1
4
|
import webbrowser
|
|
5
|
+
from collections.abc import Callable
|
|
2
6
|
from dataclasses import dataclass
|
|
3
|
-
|
|
4
|
-
import urllib.parse
|
|
5
|
-
import base64
|
|
7
|
+
|
|
6
8
|
from oauth2_cli_auth._urllib_util import _load_json
|
|
7
9
|
|
|
8
10
|
|
|
@@ -36,13 +38,15 @@ def load_oidc_config(odic_well_known_endpoint: str) -> dict:
|
|
|
36
38
|
return config
|
|
37
39
|
|
|
38
40
|
|
|
39
|
-
def open_browser(url: str) -> None:
|
|
41
|
+
def open_browser(url: str, print_open_browser_instruction: Callable[[str], None] | None = print) -> None:
|
|
40
42
|
"""
|
|
41
43
|
Open browser using webbrowser module and show message about URL open
|
|
44
|
+
:param print_open_browser_instruction: Callback to print the instructions to open the browser. Set to None in order to supress the output.
|
|
42
45
|
:param url: URL to open and display
|
|
43
46
|
:return: None
|
|
44
47
|
"""
|
|
45
|
-
|
|
48
|
+
if print_open_browser_instruction is not None:
|
|
49
|
+
print_open_browser_instruction(f"Open your browser at\n{url}")
|
|
46
50
|
webbrowser.open(url)
|
|
47
51
|
|
|
48
52
|
|
|
@@ -61,17 +65,20 @@ def get_auth_url(client_info: OAuth2ClientInfo, redirect_uri: str) -> str:
|
|
|
61
65
|
f"&response_type=code")
|
|
62
66
|
|
|
63
67
|
|
|
64
|
-
def
|
|
65
|
-
|
|
68
|
+
def exchange_code_for_response(
|
|
69
|
+
client_info: OAuth2ClientInfo,
|
|
70
|
+
redirect_uri: str,
|
|
71
|
+
code: str,
|
|
72
|
+
) -> dict:
|
|
66
73
|
"""
|
|
67
|
-
Exchange a code for an access token using the endpoints from client info
|
|
74
|
+
Exchange a code for an access token using the endpoints from client info and return the entire response
|
|
68
75
|
|
|
69
76
|
:param client_info: Info about oauth2 client
|
|
70
77
|
:param redirect_uri: Callback URL
|
|
71
78
|
:param code: Code to redeem
|
|
72
79
|
:param access_token_field: Name of the field containing the access token to use. This might differ depending on
|
|
73
|
-
|
|
74
|
-
:return:
|
|
80
|
+
the provider you are using. For example for Auth0 you have to set this to id_token
|
|
81
|
+
:return: Response from OAuth2 endpoint
|
|
75
82
|
"""
|
|
76
83
|
headers = {
|
|
77
84
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -88,4 +95,25 @@ def exchange_code_for_access_token(client_info: OAuth2ClientInfo, redirect_uri:
|
|
|
88
95
|
request = urllib.request.Request(client_info.token_url, data=encoded_data, headers=headers)
|
|
89
96
|
json_response = _load_json(request)
|
|
90
97
|
|
|
98
|
+
return json_response
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def exchange_code_for_access_token(
|
|
102
|
+
client_info: OAuth2ClientInfo,
|
|
103
|
+
redirect_uri: str,
|
|
104
|
+
code: str,
|
|
105
|
+
access_token_field: str = "access_token"
|
|
106
|
+
) -> str:
|
|
107
|
+
"""
|
|
108
|
+
Exchange a code for an access token using the endpoints from client info
|
|
109
|
+
|
|
110
|
+
:param client_info: Info about oauth2 client
|
|
111
|
+
:param redirect_uri: Callback URL
|
|
112
|
+
:param code: Code to redeem
|
|
113
|
+
:param access_token_field: Name of the field containing the access token to use. This might differ depending on
|
|
114
|
+
the provider you are using. For example for Auth0 you have to set this to id_token
|
|
115
|
+
:return: Extracted access token from response
|
|
116
|
+
"""
|
|
117
|
+
json_response = exchange_code_for_response(client_info, redirect_uri, code)
|
|
118
|
+
|
|
91
119
|
return json_response.get(access_token_field)
|
|
@@ -201,7 +201,7 @@ class OAuthCallbackHttpServer(HTTPServer):
|
|
|
201
201
|
def callback_url(self):
|
|
202
202
|
return f"http://localhost:{self.server_port}"
|
|
203
203
|
|
|
204
|
-
def wait_for_code(self, attempts: int = 3, timeout_per_attempt=10) -> Optional[
|
|
204
|
+
def wait_for_code(self, attempts: int = 3, timeout_per_attempt=10) -> Optional[str]:
|
|
205
205
|
"""
|
|
206
206
|
Wait for the server to open the callback page containing the code query parameter.
|
|
207
207
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "oauth2-cli-auth"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.3.0"
|
|
4
4
|
description = "Authenticate against OAuth2 Provider in Python CLIs"
|
|
5
5
|
authors = ["Timo Reymann <mail@timo-reymann.de>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -34,8 +34,7 @@ python = "^3.9"
|
|
|
34
34
|
[[tool.poetry.source]]
|
|
35
35
|
name = "testpypi"
|
|
36
36
|
url = "https://test.pypi.org/legacy/"
|
|
37
|
-
|
|
38
|
-
secondary = false
|
|
37
|
+
priority="explicit"
|
|
39
38
|
|
|
40
39
|
[tool.poetry.group.dev.dependencies]
|
|
41
40
|
pytest = "^7.4.3"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|