tausi 0.1.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.
tausi-0.1.0/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ - `captcha_token=` for `sign_up()`, `sign_in()` and `forgot_password()`, and `get_captcha_config()`.
6
+ - `PASSWORD_BREACHED`, `CAPTCHA_REQUIRED` and `CAPTCHA_INVALID` error codes.
7
+ - `redirect_to=` for `sign_up()`, `send_verification_email()` and `forgot_password()`: choose where email links open.
8
+ - Backend: `users.ban()`, `unban()`, `suspend(hours=|until=)`, `unsuspend()` and `bulk()`; `users.list(access=)`; `User.access`, `is_blocked` and the ban/suspension fields.
9
+ - `ACCOUNT_BANNED` and `ACCOUNT_SUSPENDED` error codes and OAuth error messages.
10
+ - `User` gains `first_name`, `last_name`, `username`, `phone_number`, `phone_number_verified`, `locale`, `timezone`, `public_metadata`, `last_sign_in_at`, and from the backend `private_metadata`, `last_sign_out_at`, `sign_in_count`, `active_sessions`, `last_active_at`, `status` and `is_signed_in`.
11
+ - `sign_up()`, `update_user()` and `users.update()` accept the new attributes (and metadata for the backend).
12
+ - `EMAIL_ALREADY_REGISTERED` and `USERNAME_TAKEN` error codes.
13
+
14
+ ## 0.1.0
15
+
16
+ - First release: `TausiBackend` (verify sessions, manage users), `TausiClient` (server-rendered sign-in), Django decorators and middleware, Django REST framework authentication, and a Flask extension.
tausi-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tausi
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.
tausi-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.5
2
+ Name: tausi
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for Tausi: verify sessions and manage users from your backend, with Django and Flask integrations.
5
+ Project-URL: Homepage, https://tausi.app
6
+ Project-URL: Documentation, https://github.com/Nelacommunity/tausi-auth/tree/main/sdks/python#readme
7
+ Project-URL: Repository, https://github.com/Nelacommunity/tausi-auth
8
+ Project-URL: Issues, https://github.com/Nelacommunity/tausi-auth/issues
9
+ Project-URL: Changelog, https://github.com/Nelacommunity/tausi-auth/blob/main/sdks/python/CHANGELOG.md
10
+ Author: Tausi
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: auth,authentication,django,flask,oauth,sessions,tausi
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Framework :: Django
16
+ Classifier: Framework :: Flask
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Topic :: Internet :: WWW/HTTP :: Session
21
+ Classifier: Topic :: Security
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.9
24
+ Provides-Extra: dev
25
+ Requires-Dist: django>=4.2; extra == 'dev'
26
+ Requires-Dist: djangorestframework>=3.15; extra == 'dev'
27
+ Requires-Dist: flask>=2.3; extra == 'dev'
28
+ Requires-Dist: pytest>=8; extra == 'dev'
29
+ Provides-Extra: django
30
+ Requires-Dist: django>=4.2; extra == 'django'
31
+ Provides-Extra: flask
32
+ Requires-Dist: flask>=2.3; extra == 'flask'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # tausi (Python)
36
+
37
+ Official Python SDK for [Tausi](https://tausi.app), with Django, Django REST framework and Flask integrations. It needs Python 3.9 or later and has **no runtime dependencies**: it uses the standard library for HTTP.
38
+
39
+ | | Key | Use it for |
40
+ | --- | --- | --- |
41
+ | `tausi.TausiBackend` | secret key `sk_…` | Protecting your API (verifying session tokens) and managing your project's users. |
42
+ | `tausi.TausiClient` | publishable key `pk_…` | Server-rendered apps where Python signs the user in and keeps their token in the session, plus scripts and CLIs. |
43
+
44
+ ```sh
45
+ pip install tausi # core
46
+ pip install "tausi[django]" # + Django
47
+ pip install "tausi[flask]" # + Flask
48
+ ```
49
+
50
+ ## Protect your API
51
+
52
+ Your frontend (built with `@tausi-auth/js`, Flutter, etc.) sends the user's session token as `Authorization: Bearer <token>`. Your backend checks it with the secret key:
53
+
54
+ ```python
55
+ import os
56
+ from tausi import TausiBackend
57
+
58
+ tausi = TausiBackend("https://tausi.app", os.environ["TAUSI_SECRET_KEY"])
59
+
60
+ auth = tausi.authenticate_request(request) # any request with .headers, or the header value itself
61
+ if auth is None:
62
+ ... # 401
63
+ print(auth.user.id, auth.user.email, auth.session.expires_at)
64
+ ```
65
+
66
+ `authenticate_request()` and `verify_session(token)` return `None` when a token is invalid, expired, revoked or belongs to another project. They raise `TausiError` only when the problem is on your side: a wrong key, a network failure or a 5xx response.
67
+
68
+ ### Django
69
+
70
+ ```python
71
+ # settings.py
72
+ TAUSI_URL = "https://tausi.app"
73
+ TAUSI_SECRET_KEY = os.environ["TAUSI_SECRET_KEY"]
74
+
75
+ # views.py
76
+ from django.http import JsonResponse
77
+ from tausi.django import tausi_required, tausi_optional
78
+
79
+ @tausi_required # 401 JSON without a valid token; works on async views too
80
+ def me(request):
81
+ return JsonResponse(request.tausi.user.to_dict())
82
+
83
+ @tausi_optional # request.tausi is an AuthResult or None
84
+ def feed(request):
85
+ ...
86
+ ```
87
+
88
+ To set `request.tausi` on every request, add `"tausi.django.TausiAuthMiddleware"` to `MIDDLEWARE`. Only requests that carry a bearer token cost a call to Tausi. When Tausi can't be reached, the decorators and middleware answer `503` with code `AUTH_UNAVAILABLE`.
89
+
90
+ Each setting falls back to the environment variable of the same name (`TAUSI_URL`, `TAUSI_SECRET_KEY`, `TAUSI_PUBLISHABLE_KEY`). `TAUSI_TIMEOUT` sets the request timeout in seconds (default 10).
91
+
92
+ ### Django REST framework
93
+
94
+ ```python
95
+ REST_FRAMEWORK = {
96
+ "DEFAULT_AUTHENTICATION_CLASSES": ["tausi.django.rest_framework.TausiAuthentication"],
97
+ "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
98
+ }
99
+ ```
100
+
101
+ In views, `request.user` is a `tausi.User` (with `is_authenticated = True`) and `request.auth` is the full `AuthResult`. Requests without a bearer token fall through to your other authentication classes.
102
+
103
+ ### Flask
104
+
105
+ ```python
106
+ from flask import Flask, g
107
+ from tausi.flask import Tausi
108
+
109
+ app = Flask(__name__)
110
+ app.config["TAUSI_URL"] = "https://tausi.app"
111
+ app.config["TAUSI_SECRET_KEY"] = os.environ["TAUSI_SECRET_KEY"]
112
+ tausi = Tausi(app) # or tausi = Tausi(); tausi.init_app(app)
113
+
114
+ @app.get("/api/me")
115
+ @tausi.required # 401 JSON without a valid token
116
+ def me():
117
+ return g.tausi.user.to_dict()
118
+
119
+ @app.get("/api/feed")
120
+ @tausi.optional # g.tausi is an AuthResult or None
121
+ def feed():
122
+ ...
123
+ ```
124
+
125
+ ## Manage users
126
+
127
+ ```python
128
+ page = tausi.users.list(q="asha", verified=True, page=1, page_size=50) # Page[User]
129
+ for user in page.items:
130
+ print(user.email, user.status, user.active_sessions, user.last_sign_in_at)
131
+
132
+ detail = tausi.users.get(user_id) # {"user": User, "accounts": [...], "sessions": [...], "recentAudit": [...]}
133
+ tausi.users.update(user_id, name="Asha", email_verified=True)
134
+ tausi.users.revoke_sessions(user_id) # sign out everywhere
135
+ tausi.users.delete(user_id)
136
+ tausi.sessions.list(page=1)
137
+ tausi.get_project() # startup check that the key works
138
+ ```
139
+
140
+ From Django you get the configured backend with `tausi.django.get_backend()`; from Flask, `tausi.backend` inside an app context.
141
+
142
+ ## Server-rendered sign-in
143
+
144
+ When your Python app renders the sign-in form itself, use `TausiClient` with the publishable key. The token stays in the server-side session and never reaches the browser.
145
+
146
+ ### Django
147
+
148
+ ```python
149
+ # settings.py: TAUSI_PUBLISHABLE_KEY = os.environ["TAUSI_PUBLISHABLE_KEY"], plus SessionMiddleware
150
+ from django.shortcuts import redirect, render
151
+ from tausi import TausiError
152
+ from tausi.django import get_client, tausi_login_required
153
+
154
+ def sign_in(request):
155
+ if request.method == "POST":
156
+ try:
157
+ get_client(request).sign_in(request.POST["email"], request.POST["password"])
158
+ return redirect(request.GET.get("next", "/"))
159
+ except TausiError as e:
160
+ return render(request, "sign_in.html", {"error": e.message, "code": e.code})
161
+ return render(request, "sign_in.html")
162
+
163
+ def sign_out(request):
164
+ get_client(request).sign_out()
165
+ return redirect("/")
166
+
167
+ @tausi_login_required # redirects to settings.LOGIN_URL with ?next=
168
+ def dashboard(request):
169
+ return render(request, "dashboard.html", {"user": request.tausi.user})
170
+ ```
171
+
172
+ ### Flask
173
+
174
+ ```python
175
+ @app.post("/sign-in")
176
+ def login():
177
+ try:
178
+ tausi.client().sign_in(request.form["email"], request.form["password"])
179
+ except TausiError as e:
180
+ return render_template("sign_in.html", error=e.message), 400
181
+ return redirect(request.args.get("next", "/"))
182
+
183
+ @app.get("/dashboard")
184
+ @tausi.login_required(login_endpoint="login")
185
+ def dashboard():
186
+ return render_template("dashboard.html", user=g.tausi.user)
187
+ ```
188
+
189
+ ### Social sign-in (PKCE)
190
+
191
+ ```python
192
+ def start_google(request):
193
+ start = get_client(request).start_oauth("google", redirect_to="https://example.com/auth/callback")
194
+ request.session["tausi_verifier"] = start.code_verifier
195
+ return redirect(start.url)
196
+
197
+ def callback(request):
198
+ verifier = request.session.pop("tausi_verifier", "")
199
+ try:
200
+ get_client(request).handle_oauth_redirect(request.build_absolute_uri(), verifier)
201
+ except TausiError as e:
202
+ return render(request, "sign_in.html", {"error": e.message})
203
+ return redirect("/")
204
+ ```
205
+
206
+ `redirect_to` must be on one of the project's allowed origins.
207
+
208
+ ### All client methods
209
+
210
+ `sign_up`, `sign_in`, `sign_out`, `get_session`, `send_verification_email`, `verify_email`, `forgot_password`, `reset_password`, `change_password`, `get_user`, `update_user`, `delete_account`, `list_sessions`, `revoke_session`, `revoke_other_sessions`, `get_providers`, `start_oauth`, `exchange_oauth_code`, `handle_oauth_redirect`.
211
+
212
+ Outside a web framework, `TausiClient` keeps the token in memory. Pass `token_store=` with any object that has `get()` and `set(token)` to keep it elsewhere; `MappingTokenStore(some_dict)` stores it in a dict-like session.
213
+
214
+ ## Errors
215
+
216
+ Every failure is a `TausiError` with `status`, `code`, `message`, `details`, `request_id` and `retry_after` (seconds, for `RATE_LIMITED`). Network failures have `status == 0` and code `NETWORK_ERROR` or `TIMEOUT`. Branch on `code`, not on the message.
217
+
218
+ ```python
219
+ try:
220
+ client.sign_in(email, password)
221
+ except TausiError as e:
222
+ if e.code == "EMAIL_NOT_VERIFIED":
223
+ ...
224
+ ```
225
+
226
+ ## Custom HTTP
227
+
228
+ The default transport is `urllib` from the standard library. To use `requests`, `httpx` or a test double, pass `transport=` to either client: a callable `(method, url, headers, body, timeout) -> tausi.HttpResponse`.
229
+
230
+ ## Development
231
+
232
+ ```sh
233
+ python -m venv .venv && .venv/bin/pip install -e ".[dev]"
234
+ .venv/bin/pytest
235
+ ```
tausi-0.1.0/README.md ADDED
@@ -0,0 +1,201 @@
1
+ # tausi (Python)
2
+
3
+ Official Python SDK for [Tausi](https://tausi.app), with Django, Django REST framework and Flask integrations. It needs Python 3.9 or later and has **no runtime dependencies**: it uses the standard library for HTTP.
4
+
5
+ | | Key | Use it for |
6
+ | --- | --- | --- |
7
+ | `tausi.TausiBackend` | secret key `sk_…` | Protecting your API (verifying session tokens) and managing your project's users. |
8
+ | `tausi.TausiClient` | publishable key `pk_…` | Server-rendered apps where Python signs the user in and keeps their token in the session, plus scripts and CLIs. |
9
+
10
+ ```sh
11
+ pip install tausi # core
12
+ pip install "tausi[django]" # + Django
13
+ pip install "tausi[flask]" # + Flask
14
+ ```
15
+
16
+ ## Protect your API
17
+
18
+ Your frontend (built with `@tausi-auth/js`, Flutter, etc.) sends the user's session token as `Authorization: Bearer <token>`. Your backend checks it with the secret key:
19
+
20
+ ```python
21
+ import os
22
+ from tausi import TausiBackend
23
+
24
+ tausi = TausiBackend("https://tausi.app", os.environ["TAUSI_SECRET_KEY"])
25
+
26
+ auth = tausi.authenticate_request(request) # any request with .headers, or the header value itself
27
+ if auth is None:
28
+ ... # 401
29
+ print(auth.user.id, auth.user.email, auth.session.expires_at)
30
+ ```
31
+
32
+ `authenticate_request()` and `verify_session(token)` return `None` when a token is invalid, expired, revoked or belongs to another project. They raise `TausiError` only when the problem is on your side: a wrong key, a network failure or a 5xx response.
33
+
34
+ ### Django
35
+
36
+ ```python
37
+ # settings.py
38
+ TAUSI_URL = "https://tausi.app"
39
+ TAUSI_SECRET_KEY = os.environ["TAUSI_SECRET_KEY"]
40
+
41
+ # views.py
42
+ from django.http import JsonResponse
43
+ from tausi.django import tausi_required, tausi_optional
44
+
45
+ @tausi_required # 401 JSON without a valid token; works on async views too
46
+ def me(request):
47
+ return JsonResponse(request.tausi.user.to_dict())
48
+
49
+ @tausi_optional # request.tausi is an AuthResult or None
50
+ def feed(request):
51
+ ...
52
+ ```
53
+
54
+ To set `request.tausi` on every request, add `"tausi.django.TausiAuthMiddleware"` to `MIDDLEWARE`. Only requests that carry a bearer token cost a call to Tausi. When Tausi can't be reached, the decorators and middleware answer `503` with code `AUTH_UNAVAILABLE`.
55
+
56
+ Each setting falls back to the environment variable of the same name (`TAUSI_URL`, `TAUSI_SECRET_KEY`, `TAUSI_PUBLISHABLE_KEY`). `TAUSI_TIMEOUT` sets the request timeout in seconds (default 10).
57
+
58
+ ### Django REST framework
59
+
60
+ ```python
61
+ REST_FRAMEWORK = {
62
+ "DEFAULT_AUTHENTICATION_CLASSES": ["tausi.django.rest_framework.TausiAuthentication"],
63
+ "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
64
+ }
65
+ ```
66
+
67
+ In views, `request.user` is a `tausi.User` (with `is_authenticated = True`) and `request.auth` is the full `AuthResult`. Requests without a bearer token fall through to your other authentication classes.
68
+
69
+ ### Flask
70
+
71
+ ```python
72
+ from flask import Flask, g
73
+ from tausi.flask import Tausi
74
+
75
+ app = Flask(__name__)
76
+ app.config["TAUSI_URL"] = "https://tausi.app"
77
+ app.config["TAUSI_SECRET_KEY"] = os.environ["TAUSI_SECRET_KEY"]
78
+ tausi = Tausi(app) # or tausi = Tausi(); tausi.init_app(app)
79
+
80
+ @app.get("/api/me")
81
+ @tausi.required # 401 JSON without a valid token
82
+ def me():
83
+ return g.tausi.user.to_dict()
84
+
85
+ @app.get("/api/feed")
86
+ @tausi.optional # g.tausi is an AuthResult or None
87
+ def feed():
88
+ ...
89
+ ```
90
+
91
+ ## Manage users
92
+
93
+ ```python
94
+ page = tausi.users.list(q="asha", verified=True, page=1, page_size=50) # Page[User]
95
+ for user in page.items:
96
+ print(user.email, user.status, user.active_sessions, user.last_sign_in_at)
97
+
98
+ detail = tausi.users.get(user_id) # {"user": User, "accounts": [...], "sessions": [...], "recentAudit": [...]}
99
+ tausi.users.update(user_id, name="Asha", email_verified=True)
100
+ tausi.users.revoke_sessions(user_id) # sign out everywhere
101
+ tausi.users.delete(user_id)
102
+ tausi.sessions.list(page=1)
103
+ tausi.get_project() # startup check that the key works
104
+ ```
105
+
106
+ From Django you get the configured backend with `tausi.django.get_backend()`; from Flask, `tausi.backend` inside an app context.
107
+
108
+ ## Server-rendered sign-in
109
+
110
+ When your Python app renders the sign-in form itself, use `TausiClient` with the publishable key. The token stays in the server-side session and never reaches the browser.
111
+
112
+ ### Django
113
+
114
+ ```python
115
+ # settings.py: TAUSI_PUBLISHABLE_KEY = os.environ["TAUSI_PUBLISHABLE_KEY"], plus SessionMiddleware
116
+ from django.shortcuts import redirect, render
117
+ from tausi import TausiError
118
+ from tausi.django import get_client, tausi_login_required
119
+
120
+ def sign_in(request):
121
+ if request.method == "POST":
122
+ try:
123
+ get_client(request).sign_in(request.POST["email"], request.POST["password"])
124
+ return redirect(request.GET.get("next", "/"))
125
+ except TausiError as e:
126
+ return render(request, "sign_in.html", {"error": e.message, "code": e.code})
127
+ return render(request, "sign_in.html")
128
+
129
+ def sign_out(request):
130
+ get_client(request).sign_out()
131
+ return redirect("/")
132
+
133
+ @tausi_login_required # redirects to settings.LOGIN_URL with ?next=
134
+ def dashboard(request):
135
+ return render(request, "dashboard.html", {"user": request.tausi.user})
136
+ ```
137
+
138
+ ### Flask
139
+
140
+ ```python
141
+ @app.post("/sign-in")
142
+ def login():
143
+ try:
144
+ tausi.client().sign_in(request.form["email"], request.form["password"])
145
+ except TausiError as e:
146
+ return render_template("sign_in.html", error=e.message), 400
147
+ return redirect(request.args.get("next", "/"))
148
+
149
+ @app.get("/dashboard")
150
+ @tausi.login_required(login_endpoint="login")
151
+ def dashboard():
152
+ return render_template("dashboard.html", user=g.tausi.user)
153
+ ```
154
+
155
+ ### Social sign-in (PKCE)
156
+
157
+ ```python
158
+ def start_google(request):
159
+ start = get_client(request).start_oauth("google", redirect_to="https://example.com/auth/callback")
160
+ request.session["tausi_verifier"] = start.code_verifier
161
+ return redirect(start.url)
162
+
163
+ def callback(request):
164
+ verifier = request.session.pop("tausi_verifier", "")
165
+ try:
166
+ get_client(request).handle_oauth_redirect(request.build_absolute_uri(), verifier)
167
+ except TausiError as e:
168
+ return render(request, "sign_in.html", {"error": e.message})
169
+ return redirect("/")
170
+ ```
171
+
172
+ `redirect_to` must be on one of the project's allowed origins.
173
+
174
+ ### All client methods
175
+
176
+ `sign_up`, `sign_in`, `sign_out`, `get_session`, `send_verification_email`, `verify_email`, `forgot_password`, `reset_password`, `change_password`, `get_user`, `update_user`, `delete_account`, `list_sessions`, `revoke_session`, `revoke_other_sessions`, `get_providers`, `start_oauth`, `exchange_oauth_code`, `handle_oauth_redirect`.
177
+
178
+ Outside a web framework, `TausiClient` keeps the token in memory. Pass `token_store=` with any object that has `get()` and `set(token)` to keep it elsewhere; `MappingTokenStore(some_dict)` stores it in a dict-like session.
179
+
180
+ ## Errors
181
+
182
+ Every failure is a `TausiError` with `status`, `code`, `message`, `details`, `request_id` and `retry_after` (seconds, for `RATE_LIMITED`). Network failures have `status == 0` and code `NETWORK_ERROR` or `TIMEOUT`. Branch on `code`, not on the message.
183
+
184
+ ```python
185
+ try:
186
+ client.sign_in(email, password)
187
+ except TausiError as e:
188
+ if e.code == "EMAIL_NOT_VERIFIED":
189
+ ...
190
+ ```
191
+
192
+ ## Custom HTTP
193
+
194
+ The default transport is `urllib` from the standard library. To use `requests`, `httpx` or a test double, pass `transport=` to either client: a callable `(method, url, headers, body, timeout) -> tausi.HttpResponse`.
195
+
196
+ ## Development
197
+
198
+ ```sh
199
+ python -m venv .venv && .venv/bin/pip install -e ".[dev]"
200
+ .venv/bin/pytest
201
+ ```
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "tausi"
7
+ version = "0.1.0"
8
+ description = "Official Python SDK for Tausi: verify sessions and manage users from your backend, with Django and Flask integrations."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.9"
13
+ authors = [{ name = "Tausi" }]
14
+ keywords = ["tausi", "auth", "authentication", "sessions", "oauth", "django", "flask"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Framework :: Django",
18
+ "Framework :: Flask",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Internet :: WWW/HTTP :: Session",
23
+ "Topic :: Security",
24
+ "Typing :: Typed",
25
+ ]
26
+ dependencies = []
27
+
28
+ [project.optional-dependencies]
29
+ django = ["django>=4.2"]
30
+ flask = ["flask>=2.3"]
31
+ dev = ["pytest>=8", "django>=4.2", "flask>=2.3", "djangorestframework>=3.15"]
32
+
33
+ [project.urls]
34
+ Homepage = "https://tausi.app"
35
+ Documentation = "https://github.com/Nelacommunity/tausi-auth/tree/main/sdks/python#readme"
36
+ Repository = "https://github.com/Nelacommunity/tausi-auth"
37
+ Issues = "https://github.com/Nelacommunity/tausi-auth/issues"
38
+ Changelog = "https://github.com/Nelacommunity/tausi-auth/blob/main/sdks/python/CHANGELOG.md"
39
+
40
+ [tool.hatch.build.targets.wheel]
41
+ packages = ["src/tausi"]
42
+
43
+ [tool.hatch.build.targets.sdist]
44
+ include = ["src/tausi", "tests", "README.md", "CHANGELOG.md", "LICENSE"]
45
+
46
+ [tool.pytest.ini_options]
47
+ testpaths = ["tests"]
@@ -0,0 +1,39 @@
1
+ """Official Python SDK for Tausi.
2
+
3
+ * :class:`TausiBackend` (secret key ``sk_...``): verify session tokens and manage users.
4
+ * :class:`TausiClient` (publishable key ``pk_...``): sign users in from server-rendered apps, scripts and CLIs.
5
+ * ``tausi.django`` and ``tausi.flask``: framework integrations.
6
+ """
7
+
8
+ from ._http import SDK_VERSION, HttpResponse, Transport, urllib_transport
9
+ from .backend import TausiBackend, bearer_token
10
+ from .client import TausiClient, oauth_error_message, parse_oauth_redirect, random_device_id
11
+ from .errors import TausiError
12
+ from .models import AuthResult, OAuthStart, Page, Session, User
13
+ from .pkce import create_pkce
14
+ from .token_store import MappingTokenStore, MemoryTokenStore, TokenStore
15
+
16
+ __version__ = SDK_VERSION
17
+
18
+ __all__ = [
19
+ "SDK_VERSION",
20
+ "AuthResult",
21
+ "HttpResponse",
22
+ "MappingTokenStore",
23
+ "MemoryTokenStore",
24
+ "OAuthStart",
25
+ "Page",
26
+ "Session",
27
+ "TausiBackend",
28
+ "TausiClient",
29
+ "TausiError",
30
+ "TokenStore",
31
+ "Transport",
32
+ "User",
33
+ "bearer_token",
34
+ "create_pkce",
35
+ "oauth_error_message",
36
+ "parse_oauth_redirect",
37
+ "random_device_id",
38
+ "urllib_transport",
39
+ ]