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.
- supabase_auth-2.4.2/LICENSE +21 -0
- supabase_auth-2.4.2/PKG-INFO +122 -0
- supabase_auth-2.4.2/README.md +98 -0
- supabase_auth-2.4.2/pyproject.toml +50 -0
- supabase_auth-2.4.2/supabase_auth/__init__.py +13 -0
- supabase_auth-2.4.2/supabase_auth/_async/__init__.py +1 -0
- supabase_auth-2.4.2/supabase_auth/_async/gotrue_admin_api.py +180 -0
- supabase_auth-2.4.2/supabase_auth/_async/gotrue_admin_mfa_api.py +32 -0
- supabase_auth-2.4.2/supabase_auth/_async/gotrue_base_api.py +118 -0
- supabase_auth-2.4.2/supabase_auth/_async/gotrue_client.py +985 -0
- supabase_auth-2.4.2/supabase_auth/_async/gotrue_mfa_api.py +94 -0
- supabase_auth-2.4.2/supabase_auth/_async/storage.py +34 -0
- supabase_auth-2.4.2/supabase_auth/_sync/__init__.py +1 -0
- supabase_auth-2.4.2/supabase_auth/_sync/api.py +649 -0
- supabase_auth-2.4.2/supabase_auth/_sync/client.py +641 -0
- supabase_auth-2.4.2/supabase_auth/_sync/gotrue_admin_api.py +180 -0
- supabase_auth-2.4.2/supabase_auth/_sync/gotrue_admin_mfa_api.py +32 -0
- supabase_auth-2.4.2/supabase_auth/_sync/gotrue_base_api.py +118 -0
- supabase_auth-2.4.2/supabase_auth/_sync/gotrue_client.py +981 -0
- supabase_auth-2.4.2/supabase_auth/_sync/gotrue_mfa_api.py +94 -0
- supabase_auth-2.4.2/supabase_auth/_sync/storage.py +34 -0
- supabase_auth-2.4.2/supabase_auth/constants.py +14 -0
- supabase_auth-2.4.2/supabase_auth/errors.py +115 -0
- supabase_auth-2.4.2/supabase_auth/helpers.py +160 -0
- supabase_auth-2.4.2/supabase_auth/http_clients.py +9 -0
- supabase_auth-2.4.2/supabase_auth/timer.py +44 -0
- 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
|
+
[](https://opensource.org/licenses/MIT)
|
|
27
|
+
[](https://github.com/supabase-community/gotrue-py/actions/workflows/ci.yml)
|
|
28
|
+
[](https://pypi.org/project/gotrue)
|
|
29
|
+
[](https://pypi.org/project/gotrue)
|
|
30
|
+
[](https://codecov.io/gh/supabase-community/gotrue-py)
|
|
31
|
+
[](https://github.com/supabase-community/gotrue-py/commits)
|
|
32
|
+
[](https://github.com/supabase-community/gotrue-py/commits)
|
|
33
|
+
[](https://github.com/supabase-community/gotrue-py/stargazers)
|
|
34
|
+
[](https://github.com/supabase-community/gotrue-py/network/members)
|
|
35
|
+
[](https://github.com/supabase-community/gotrue-py)
|
|
36
|
+
[](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
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://github.com/supabase-community/gotrue-py/actions/workflows/ci.yml)
|
|
5
|
+
[](https://pypi.org/project/gotrue)
|
|
6
|
+
[](https://pypi.org/project/gotrue)
|
|
7
|
+
[](https://codecov.io/gh/supabase-community/gotrue-py)
|
|
8
|
+
[](https://github.com/supabase-community/gotrue-py/commits)
|
|
9
|
+
[](https://github.com/supabase-community/gotrue-py/commits)
|
|
10
|
+
[](https://github.com/supabase-community/gotrue-py/stargazers)
|
|
11
|
+
[](https://github.com/supabase-community/gotrue-py/network/members)
|
|
12
|
+
[](https://github.com/supabase-community/gotrue-py)
|
|
13
|
+
[](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)
|