supabase-auth 2.4.2__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.
Files changed (27) hide show
  1. supabase_auth-2.4.2/LICENSE +21 -0
  2. supabase_auth-2.4.2/PKG-INFO +122 -0
  3. supabase_auth-2.4.2/README.md +98 -0
  4. supabase_auth-2.4.2/pyproject.toml +50 -0
  5. supabase_auth-2.4.2/supabase_auth/__init__.py +13 -0
  6. supabase_auth-2.4.2/supabase_auth/_async/__init__.py +1 -0
  7. supabase_auth-2.4.2/supabase_auth/_async/gotrue_admin_api.py +180 -0
  8. supabase_auth-2.4.2/supabase_auth/_async/gotrue_admin_mfa_api.py +32 -0
  9. supabase_auth-2.4.2/supabase_auth/_async/gotrue_base_api.py +118 -0
  10. supabase_auth-2.4.2/supabase_auth/_async/gotrue_client.py +985 -0
  11. supabase_auth-2.4.2/supabase_auth/_async/gotrue_mfa_api.py +94 -0
  12. supabase_auth-2.4.2/supabase_auth/_async/storage.py +34 -0
  13. supabase_auth-2.4.2/supabase_auth/_sync/__init__.py +1 -0
  14. supabase_auth-2.4.2/supabase_auth/_sync/api.py +649 -0
  15. supabase_auth-2.4.2/supabase_auth/_sync/client.py +641 -0
  16. supabase_auth-2.4.2/supabase_auth/_sync/gotrue_admin_api.py +180 -0
  17. supabase_auth-2.4.2/supabase_auth/_sync/gotrue_admin_mfa_api.py +32 -0
  18. supabase_auth-2.4.2/supabase_auth/_sync/gotrue_base_api.py +118 -0
  19. supabase_auth-2.4.2/supabase_auth/_sync/gotrue_client.py +981 -0
  20. supabase_auth-2.4.2/supabase_auth/_sync/gotrue_mfa_api.py +94 -0
  21. supabase_auth-2.4.2/supabase_auth/_sync/storage.py +34 -0
  22. supabase_auth-2.4.2/supabase_auth/constants.py +14 -0
  23. supabase_auth-2.4.2/supabase_auth/errors.py +115 -0
  24. supabase_auth-2.4.2/supabase_auth/helpers.py +160 -0
  25. supabase_auth-2.4.2/supabase_auth/http_clients.py +9 -0
  26. supabase_auth-2.4.2/supabase_auth/timer.py +44 -0
  27. supabase_auth-2.4.2/supabase_auth/types.py +711 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Joel Lee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.1
2
+ Name: supabase_auth
3
+ Version: 2.4.2
4
+ Summary: Python Client Library for Supabase Auth
5
+ Home-page: https://github.com/supabase-community/auth-py
6
+ License: MIT
7
+ Author: Joel Lee
8
+ Author-email: joel@joellee.org
9
+ Requires-Python: >=3.8,<4.0
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Dist: httpx (>=0.23,<0.28)
19
+ Requires-Dist: pydantic (>=1.10,<3)
20
+ Project-URL: Documentation, https://github.com/supabase-community/auth-py
21
+ Project-URL: Repository, https://github.com/supabase-community/auth-py
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Auth-py
25
+
26
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?label=license)](https://opensource.org/licenses/MIT)
27
+ [![CI](https://github.com/supabase-community/gotrue-py/actions/workflows/ci.yml/badge.svg)](https://github.com/supabase-community/gotrue-py/actions/workflows/ci.yml)
28
+ [![Python](https://img.shields.io/pypi/pyversions/gotrue)](https://pypi.org/project/gotrue)
29
+ [![Version](https://img.shields.io/pypi/v/gotrue?color=%2334D058)](https://pypi.org/project/gotrue)
30
+ [![Codecov](https://codecov.io/gh/supabase-community/gotrue-py/branch/main/graph/badge.svg)](https://codecov.io/gh/supabase-community/gotrue-py)
31
+ [![Last commit](https://img.shields.io/github/last-commit/supabase-community/gotrue-py.svg?style=flat)](https://github.com/supabase-community/gotrue-py/commits)
32
+ [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/supabase-community/gotrue-py)](https://github.com/supabase-community/gotrue-py/commits)
33
+ [![Github Stars](https://img.shields.io/github/stars/supabase-community/gotrue-py?style=flat&logo=github)](https://github.com/supabase-community/gotrue-py/stargazers)
34
+ [![Github Forks](https://img.shields.io/github/forks/supabase-community/gotrue-py?style=flat&logo=github)](https://github.com/supabase-community/gotrue-py/network/members)
35
+ [![Github Watchers](https://img.shields.io/github/watchers/supabase-community/gotrue-py?style=flat&logo=github)](https://github.com/supabase-community/gotrue-py)
36
+ [![GitHub contributors](https://img.shields.io/github/contributors/supabase-community/gotrue-py)](https://github.com/supabase-community/gotrue-py/graphs/contributors)
37
+
38
+ This is a Python port of the [supabase js gotrue client](https://github.com/supabase/gotrue-js). The current state is that there is a features parity but with small differences that are mentioned in the section **Differences to the JS client**. As of December 14th, we renamed to repo from `gotrue-py` to `auth-py` to mirror the changes in the JavaScript library.
39
+
40
+ ## Installation
41
+
42
+ We are still working on making the `supabase_auth` python library more user-friendly. For now here are some sparse notes on how to install the module.
43
+
44
+ ### Poetry
45
+
46
+ ```bash
47
+ poetry add supabase_auth
48
+ ```
49
+
50
+ ### Pip
51
+
52
+ ```bash
53
+ pip install supabase_auth
54
+ ```
55
+
56
+ ## Differences to the JS client
57
+
58
+ It should be noted there are differences to the [JS client](https://github.com/supabase/gotrue-js). If you feel particulaly strongly about them and want to motivate a change, feel free to make a GitHub issue and we can discuss it there.
59
+
60
+ Firstly, feature pairity is not 100% with the [JS client](https://github.com/supabase/gotrue-js). In most cases we match the methods and attributes of the [JS client](https://github.com/supabase/gotrue-js) and api classes, but is some places (e.g for browser specific code) it didn't make sense to port the code line for line.
61
+
62
+ There is also a divergence in terms of how errors are raised. In the [JS client](https://github.com/supabase/gotrue-js), the errors are returned as part of the object, which the user can choose to process in whatever way they see fit. In this Python client, we raise the errors directly where they originate, as it was felt this was more Pythonic and adhered to the idioms of the language more directly.
63
+
64
+ In JS we return the error, but in Python we just raise it.
65
+
66
+ ```js
67
+ const { data, error } = client.sign_up(...)
68
+ ```
69
+
70
+ The other key difference is we do not use pascalCase to encode variable and method names. Instead we use the snake_case convention adopted in the Python language.
71
+
72
+ Also, the `supabase_auth` library for Python parses the date-time string into `datetime` Python objects. The [JS client](https://github.com/supabase/gotrue-js) keeps the date-time as strings.
73
+
74
+ ## Usage (outdated)
75
+
76
+ **Important:** This section is outdated, you can be guided by the [JS client documentation](https://supabase.github.io/gotrue-js) because this Python client has a lot of parity with the JS client.
77
+
78
+ To instantiate the client, you'll need the URL and any request headers at a minimum.
79
+
80
+ ```python
81
+ from supabase_auth import SyncGoTrueClient
82
+
83
+ headers = {
84
+ "apiKey": "my-mega-awesome-api-key",
85
+ # ... any other headers you might need.
86
+ }
87
+ client: SyncGoTrueClient = SyncGoTrueClient(url="www.genericauthwebsite.com", headers=headers)
88
+ ```
89
+
90
+ To send a magic email link to the user, just provide the email kwarg to the `sign_in` method:
91
+
92
+ ```python
93
+ user: Dict[str, Any] = client.sign_up(email="example@gmail.com")
94
+ ```
95
+
96
+ To login with email and password, provide both to the `sign_in` method:
97
+
98
+ ```python
99
+ user: Dict[str, Any] = client.sign_up(email="example@gmail.com", password="*********")
100
+ ```
101
+
102
+ To sign out of the logged in user, call the `sign_out` method. We can then assert that the session and user are null values.
103
+
104
+ ```python
105
+ client.sign_out()
106
+ assert client.user() is None
107
+ assert client.session() is None
108
+ ```
109
+
110
+ We can refesh a users session.
111
+
112
+ ```python
113
+ # The user should already be signed in at this stage.
114
+ user = client.refresh_session()
115
+ assert client.user() is not None
116
+ assert client.session() is not None
117
+ ```
118
+
119
+ ## Contributions
120
+
121
+ We would be immensely grateful for any contributions to this project.
122
+
@@ -0,0 +1,98 @@
1
+ # Auth-py
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?label=license)](https://opensource.org/licenses/MIT)
4
+ [![CI](https://github.com/supabase-community/gotrue-py/actions/workflows/ci.yml/badge.svg)](https://github.com/supabase-community/gotrue-py/actions/workflows/ci.yml)
5
+ [![Python](https://img.shields.io/pypi/pyversions/gotrue)](https://pypi.org/project/gotrue)
6
+ [![Version](https://img.shields.io/pypi/v/gotrue?color=%2334D058)](https://pypi.org/project/gotrue)
7
+ [![Codecov](https://codecov.io/gh/supabase-community/gotrue-py/branch/main/graph/badge.svg)](https://codecov.io/gh/supabase-community/gotrue-py)
8
+ [![Last commit](https://img.shields.io/github/last-commit/supabase-community/gotrue-py.svg?style=flat)](https://github.com/supabase-community/gotrue-py/commits)
9
+ [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/supabase-community/gotrue-py)](https://github.com/supabase-community/gotrue-py/commits)
10
+ [![Github Stars](https://img.shields.io/github/stars/supabase-community/gotrue-py?style=flat&logo=github)](https://github.com/supabase-community/gotrue-py/stargazers)
11
+ [![Github Forks](https://img.shields.io/github/forks/supabase-community/gotrue-py?style=flat&logo=github)](https://github.com/supabase-community/gotrue-py/network/members)
12
+ [![Github Watchers](https://img.shields.io/github/watchers/supabase-community/gotrue-py?style=flat&logo=github)](https://github.com/supabase-community/gotrue-py)
13
+ [![GitHub contributors](https://img.shields.io/github/contributors/supabase-community/gotrue-py)](https://github.com/supabase-community/gotrue-py/graphs/contributors)
14
+
15
+ This is a Python port of the [supabase js gotrue client](https://github.com/supabase/gotrue-js). The current state is that there is a features parity but with small differences that are mentioned in the section **Differences to the JS client**. As of December 14th, we renamed to repo from `gotrue-py` to `auth-py` to mirror the changes in the JavaScript library.
16
+
17
+ ## Installation
18
+
19
+ We are still working on making the `supabase_auth` python library more user-friendly. For now here are some sparse notes on how to install the module.
20
+
21
+ ### Poetry
22
+
23
+ ```bash
24
+ poetry add supabase_auth
25
+ ```
26
+
27
+ ### Pip
28
+
29
+ ```bash
30
+ pip install supabase_auth
31
+ ```
32
+
33
+ ## Differences to the JS client
34
+
35
+ It should be noted there are differences to the [JS client](https://github.com/supabase/gotrue-js). If you feel particulaly strongly about them and want to motivate a change, feel free to make a GitHub issue and we can discuss it there.
36
+
37
+ Firstly, feature pairity is not 100% with the [JS client](https://github.com/supabase/gotrue-js). In most cases we match the methods and attributes of the [JS client](https://github.com/supabase/gotrue-js) and api classes, but is some places (e.g for browser specific code) it didn't make sense to port the code line for line.
38
+
39
+ There is also a divergence in terms of how errors are raised. In the [JS client](https://github.com/supabase/gotrue-js), the errors are returned as part of the object, which the user can choose to process in whatever way they see fit. In this Python client, we raise the errors directly where they originate, as it was felt this was more Pythonic and adhered to the idioms of the language more directly.
40
+
41
+ In JS we return the error, but in Python we just raise it.
42
+
43
+ ```js
44
+ const { data, error } = client.sign_up(...)
45
+ ```
46
+
47
+ The other key difference is we do not use pascalCase to encode variable and method names. Instead we use the snake_case convention adopted in the Python language.
48
+
49
+ Also, the `supabase_auth` library for Python parses the date-time string into `datetime` Python objects. The [JS client](https://github.com/supabase/gotrue-js) keeps the date-time as strings.
50
+
51
+ ## Usage (outdated)
52
+
53
+ **Important:** This section is outdated, you can be guided by the [JS client documentation](https://supabase.github.io/gotrue-js) because this Python client has a lot of parity with the JS client.
54
+
55
+ To instantiate the client, you'll need the URL and any request headers at a minimum.
56
+
57
+ ```python
58
+ from supabase_auth import SyncGoTrueClient
59
+
60
+ headers = {
61
+ "apiKey": "my-mega-awesome-api-key",
62
+ # ... any other headers you might need.
63
+ }
64
+ client: SyncGoTrueClient = SyncGoTrueClient(url="www.genericauthwebsite.com", headers=headers)
65
+ ```
66
+
67
+ To send a magic email link to the user, just provide the email kwarg to the `sign_in` method:
68
+
69
+ ```python
70
+ user: Dict[str, Any] = client.sign_up(email="example@gmail.com")
71
+ ```
72
+
73
+ To login with email and password, provide both to the `sign_in` method:
74
+
75
+ ```python
76
+ user: Dict[str, Any] = client.sign_up(email="example@gmail.com", password="*********")
77
+ ```
78
+
79
+ To sign out of the logged in user, call the `sign_out` method. We can then assert that the session and user are null values.
80
+
81
+ ```python
82
+ client.sign_out()
83
+ assert client.user() is None
84
+ assert client.session() is None
85
+ ```
86
+
87
+ We can refesh a users session.
88
+
89
+ ```python
90
+ # The user should already be signed in at this stage.
91
+ user = client.refresh_session()
92
+ assert client.user() is not None
93
+ assert client.session() is not None
94
+ ```
95
+
96
+ ## Contributions
97
+
98
+ We would be immensely grateful for any contributions to this project.
@@ -0,0 +1,50 @@
1
+ [tool.poetry]
2
+ name = "supabase_auth"
3
+ version = "2.4.2"
4
+ description = "Python Client Library for Supabase Auth"
5
+ authors = ["Joel Lee <joel@joellee.org>"]
6
+ homepage = "https://github.com/supabase-community/auth-py"
7
+ repository = "https://github.com/supabase-community/auth-py"
8
+ documentation = "https://github.com/supabase-community/auth-py"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Operating System :: OS Independent"
15
+ ]
16
+
17
+ [tool.poetry.dependencies]
18
+ python = "^3.8"
19
+ httpx = ">=0.23,<0.28"
20
+ pydantic = ">=1.10,<3"
21
+
22
+ [tool.poetry.dev-dependencies]
23
+ pytest = "^8.1.0"
24
+ flake8 = "^5.0.4"
25
+ black = "^24.3.0"
26
+ isort = "^5.12.0"
27
+ pre-commit = "^3.4.0"
28
+ pytest-cov = "^4.0.0"
29
+ pytest-depends = "^1.0.1"
30
+ pytest-asyncio = "^0.23.5"
31
+ Faker = "^23.3.0"
32
+ unasync-cli = "^0.0.9"
33
+ python-semantic-release = "^9.1.1"
34
+
35
+ [tool.poetry.group.dev.dependencies]
36
+ pygithub = ">=1.57,<3.0"
37
+
38
+ [tool.semantic_release]
39
+ version_variables = ["supabase_auth/__init__.py:__version__"]
40
+ version_toml = ["pyproject.toml:tool.poetry.version"]
41
+ major_on_zero = false
42
+ commit_message = "chore(release): bump version to v{version}"
43
+ build_command = "curl -sSL https://install.python-poetry.org | python - && export PATH=\"/github/home/.local/bin:$PATH\" && poetry install && poetry build"
44
+ upload_to_vcs_release = true
45
+ branch = "main"
46
+ changelog_components = "semantic_release.changelog.changelog_headers,semantic_release.changelog.compare_url"
47
+
48
+ [build-system]
49
+ requires = ["poetry-core>=1.0.0"]
50
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ __version__ = "2.4.2"
4
+
5
+ from ._async.gotrue_admin_api import AsyncGoTrueAdminAPI # type: ignore # noqa: F401
6
+ from ._async.gotrue_client import AsyncGoTrueClient # type: ignore # noqa: F401
7
+ from ._async.storage import AsyncMemoryStorage # type: ignore # noqa: F401
8
+ from ._async.storage import AsyncSupportedStorage # type: ignore # noqa: F401
9
+ from ._sync.gotrue_admin_api import SyncGoTrueAdminAPI # type: ignore # noqa: F401
10
+ from ._sync.gotrue_client import SyncGoTrueClient # type: ignore # noqa: F401
11
+ from ._sync.storage import SyncMemoryStorage # type: ignore # noqa: F401
12
+ from ._sync.storage import SyncSupportedStorage # type: ignore # noqa: F401
13
+ from .types import * # type: ignore # noqa: F401, F403
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,180 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from typing import Dict, List, Union
5
+
6
+ from ..helpers import model_validate, parse_link_response, parse_user_response
7
+ from ..http_clients import AsyncClient
8
+ from ..types import (
9
+ AdminUserAttributes,
10
+ AuthMFAAdminDeleteFactorParams,
11
+ AuthMFAAdminDeleteFactorResponse,
12
+ AuthMFAAdminListFactorsParams,
13
+ AuthMFAAdminListFactorsResponse,
14
+ GenerateLinkParams,
15
+ GenerateLinkResponse,
16
+ Options,
17
+ SignOutScope,
18
+ User,
19
+ UserResponse,
20
+ )
21
+ from .gotrue_admin_mfa_api import AsyncGoTrueAdminMFAAPI
22
+ from .gotrue_base_api import AsyncGoTrueBaseAPI
23
+
24
+
25
+ class AsyncGoTrueAdminAPI(AsyncGoTrueBaseAPI):
26
+ def __init__(
27
+ self,
28
+ *,
29
+ url: str = "",
30
+ headers: Dict[str, str] = {},
31
+ http_client: Union[AsyncClient, None] = None,
32
+ ) -> None:
33
+ AsyncGoTrueBaseAPI.__init__(
34
+ self,
35
+ url=url,
36
+ headers=headers,
37
+ http_client=http_client,
38
+ )
39
+ self.mfa = AsyncGoTrueAdminMFAAPI()
40
+ self.mfa.list_factors = self._list_factors
41
+ self.mfa.delete_factor = self._delete_factor
42
+
43
+ async def sign_out(self, jwt: str, scope: SignOutScope = "global") -> None:
44
+ """
45
+ Removes a logged-in session.
46
+ """
47
+ return await self._request(
48
+ "POST",
49
+ "logout",
50
+ query={"scope": scope},
51
+ jwt=jwt,
52
+ no_resolve_json=True,
53
+ )
54
+
55
+ async def invite_user_by_email(
56
+ self,
57
+ email: str,
58
+ options: Options = {},
59
+ ) -> UserResponse:
60
+ """
61
+ Sends an invite link to an email address.
62
+ """
63
+ return await self._request(
64
+ "POST",
65
+ "invite",
66
+ body={"email": email, "data": options.get("data")},
67
+ redirect_to=options.get("redirect_to"),
68
+ xform=parse_user_response,
69
+ )
70
+
71
+ async def generate_link(self, params: GenerateLinkParams) -> GenerateLinkResponse:
72
+ """
73
+ Generates email links and OTPs to be sent via a custom email provider.
74
+ """
75
+ return await self._request(
76
+ "POST",
77
+ "admin/generate_link",
78
+ body={
79
+ "type": params.get("type"),
80
+ "email": params.get("email"),
81
+ "password": params.get("password"),
82
+ "new_email": params.get("new_email"),
83
+ "data": params.get("options", {}).get("data"),
84
+ },
85
+ redirect_to=params.get("options", {}).get("redirect_to"),
86
+ xform=parse_link_response,
87
+ )
88
+
89
+ # User Admin API
90
+
91
+ async def create_user(self, attributes: AdminUserAttributes) -> UserResponse:
92
+ """
93
+ Creates a new user.
94
+
95
+ This function should only be called on a server.
96
+ Never expose your `service_role` key in the browser.
97
+ """
98
+ return await self._request(
99
+ "POST",
100
+ "admin/users",
101
+ body=attributes,
102
+ xform=parse_user_response,
103
+ )
104
+
105
+ async def list_users(self, page: int = None, per_page: int = None) -> List[User]:
106
+ """
107
+ Get a list of users.
108
+
109
+ This function should only be called on a server.
110
+ Never expose your `service_role` key in the browser.
111
+ """
112
+ return await self._request(
113
+ "GET",
114
+ "admin/users",
115
+ query={"page": page, "per_page": per_page},
116
+ xform=lambda data: [model_validate(User, user) for user in data["users"]]
117
+ if "users" in data
118
+ else [],
119
+ )
120
+
121
+ async def get_user_by_id(self, uid: str) -> UserResponse:
122
+ """
123
+ Get user by id.
124
+
125
+ This function should only be called on a server.
126
+ Never expose your `service_role` key in the browser.
127
+ """
128
+ return await self._request(
129
+ "GET",
130
+ f"admin/users/{uid}",
131
+ xform=parse_user_response,
132
+ )
133
+
134
+ async def update_user_by_id(
135
+ self,
136
+ uid: str,
137
+ attributes: AdminUserAttributes,
138
+ ) -> UserResponse:
139
+ """
140
+ Updates the user data.
141
+
142
+ This function should only be called on a server.
143
+ Never expose your `service_role` key in the browser.
144
+ """
145
+ return await self._request(
146
+ "PUT",
147
+ f"admin/users/{uid}",
148
+ body=attributes,
149
+ xform=parse_user_response,
150
+ )
151
+
152
+ async def delete_user(self, id: str, should_soft_delete: bool = False) -> None:
153
+ """
154
+ Delete a user. Requires a `service_role` key.
155
+
156
+ This function should only be called on a server.
157
+ Never expose your `service_role` key in the browser.
158
+ """
159
+ body = {"should_soft_delete": should_soft_delete}
160
+ return await self._request("DELETE", f"admin/users/{id}", body=body)
161
+
162
+ async def _list_factors(
163
+ self,
164
+ params: AuthMFAAdminListFactorsParams,
165
+ ) -> AuthMFAAdminListFactorsResponse:
166
+ return await self._request(
167
+ "GET",
168
+ f"admin/users/{params.get('user_id')}/factors",
169
+ xform=partial(model_validate, AuthMFAAdminListFactorsResponse),
170
+ )
171
+
172
+ async def _delete_factor(
173
+ self,
174
+ params: AuthMFAAdminDeleteFactorParams,
175
+ ) -> AuthMFAAdminDeleteFactorResponse:
176
+ return await self._request(
177
+ "DELETE",
178
+ f"admin/users/{params.get('user_id')}/factors/{params.get('factor_id')}",
179
+ xform=partial(model_validate, AuthMFAAdminDeleteFactorResponse),
180
+ )
@@ -0,0 +1,32 @@
1
+ from ..types import (
2
+ AuthMFAAdminDeleteFactorParams,
3
+ AuthMFAAdminDeleteFactorResponse,
4
+ AuthMFAAdminListFactorsParams,
5
+ AuthMFAAdminListFactorsResponse,
6
+ )
7
+
8
+
9
+ class AsyncGoTrueAdminMFAAPI:
10
+ """
11
+ Contains the full multi-factor authentication administration API.
12
+ """
13
+
14
+ async def list_factors(
15
+ self,
16
+ params: AuthMFAAdminListFactorsParams,
17
+ ) -> AuthMFAAdminListFactorsResponse:
18
+ """
19
+ Lists all factors attached to a user.
20
+ """
21
+ raise NotImplementedError() # pragma: no cover
22
+
23
+ async def delete_factor(
24
+ self,
25
+ params: AuthMFAAdminDeleteFactorParams,
26
+ ) -> AuthMFAAdminDeleteFactorResponse:
27
+ """
28
+ Deletes a factor on a user. This will log the user out of all active
29
+ sessions (if the deleted factor was verified). There's no need to delete
30
+ unverified factors.
31
+ """
32
+ raise NotImplementedError() # pragma: no cover
@@ -0,0 +1,118 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable, Dict, TypeVar, Union, overload
4
+
5
+ from httpx import Response
6
+ from pydantic import BaseModel
7
+ from typing_extensions import Literal, Self
8
+
9
+ from ..helpers import handle_exception, model_dump
10
+ from ..http_clients import AsyncClient
11
+
12
+ T = TypeVar("T")
13
+
14
+
15
+ class AsyncGoTrueBaseAPI:
16
+ def __init__(
17
+ self,
18
+ *,
19
+ url: str,
20
+ headers: Dict[str, str],
21
+ http_client: Union[AsyncClient, None],
22
+ ):
23
+ self._url = url
24
+ self._headers = headers
25
+ self._http_client = http_client or AsyncClient()
26
+
27
+ async def __aenter__(self) -> Self:
28
+ return self
29
+
30
+ async def __aexit__(self, exc_t, exc_v, exc_tb) -> None:
31
+ await self.close()
32
+
33
+ async def close(self) -> None:
34
+ await self._http_client.aclose()
35
+
36
+ @overload
37
+ async def _request(
38
+ self,
39
+ method: Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
40
+ path: str,
41
+ *,
42
+ jwt: Union[str, None] = None,
43
+ redirect_to: Union[str, None] = None,
44
+ headers: Union[Dict[str, str], None] = None,
45
+ query: Union[Dict[str, str], None] = None,
46
+ body: Union[Any, None] = None,
47
+ no_resolve_json: Literal[False] = False,
48
+ xform: Callable[[Any], T],
49
+ ) -> T:
50
+ ... # pragma: no cover
51
+
52
+ @overload
53
+ async def _request(
54
+ self,
55
+ method: Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
56
+ path: str,
57
+ *,
58
+ jwt: Union[str, None] = None,
59
+ redirect_to: Union[str, None] = None,
60
+ headers: Union[Dict[str, str], None] = None,
61
+ query: Union[Dict[str, str], None] = None,
62
+ body: Union[Any, None] = None,
63
+ no_resolve_json: Literal[True],
64
+ xform: Callable[[Response], T],
65
+ ) -> T:
66
+ ... # pragma: no cover
67
+
68
+ @overload
69
+ async def _request(
70
+ self,
71
+ method: Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
72
+ path: str,
73
+ *,
74
+ jwt: Union[str, None] = None,
75
+ redirect_to: Union[str, None] = None,
76
+ headers: Union[Dict[str, str], None] = None,
77
+ query: Union[Dict[str, str], None] = None,
78
+ body: Union[Any, None] = None,
79
+ no_resolve_json: bool = False,
80
+ ) -> None:
81
+ ... # pragma: no cover
82
+
83
+ async def _request(
84
+ self,
85
+ method: Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
86
+ path: str,
87
+ *,
88
+ jwt: Union[str, None] = None,
89
+ redirect_to: Union[str, None] = None,
90
+ headers: Union[Dict[str, str], None] = None,
91
+ query: Union[Dict[str, str], None] = None,
92
+ body: Union[Any, None] = None,
93
+ no_resolve_json: bool = False,
94
+ xform: Union[Callable[[Any], T], None] = None,
95
+ ) -> Union[T, None]:
96
+ url = f"{self._url}/{path}"
97
+ headers = {**self._headers, **(headers or {})}
98
+ if "Content-Type" not in headers:
99
+ headers["Content-Type"] = "application/json;charset=UTF-8"
100
+ if jwt:
101
+ headers["Authorization"] = f"Bearer {jwt}"
102
+ query = query or {}
103
+ if redirect_to:
104
+ query["redirect_to"] = redirect_to
105
+ try:
106
+ response = await self._http_client.request(
107
+ method,
108
+ url,
109
+ headers=headers,
110
+ params=query,
111
+ json=model_dump(body) if isinstance(body, BaseModel) else body,
112
+ )
113
+ response.raise_for_status()
114
+ result = response if no_resolve_json else response.json()
115
+ if xform:
116
+ return xform(result)
117
+ except Exception as e:
118
+ raise handle_exception(e)