fastapi-rebac 0.1.0a1__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 (83) hide show
  1. fastapi_rebac-0.1.0a1/LICENSE +21 -0
  2. fastapi_rebac-0.1.0a1/PKG-INFO +398 -0
  3. fastapi_rebac-0.1.0a1/README.md +322 -0
  4. fastapi_rebac-0.1.0a1/fastapi_rebac/__init__.py +24 -0
  5. fastapi_rebac-0.1.0a1/fastapi_rebac/__version__.py +12 -0
  6. fastapi_rebac-0.1.0a1/fastapi_rebac/access.py +236 -0
  7. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/__init__.py +3 -0
  8. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/api.py +30 -0
  9. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/auth_tables.py +55 -0
  10. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/groups.py +657 -0
  11. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/login.py +259 -0
  12. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/redirects.py +69 -0
  13. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/resources.py +395 -0
  14. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/router.py +30 -0
  15. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/suspicious_alerts.py +59 -0
  16. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/users.py +874 -0
  17. fastapi_rebac-0.1.0a1/fastapi_rebac/admin/utils.py +918 -0
  18. fastapi_rebac-0.1.0a1/fastapi_rebac/anomaly/__init__.py +36 -0
  19. fastapi_rebac-0.1.0a1/fastapi_rebac/anomaly/config.py +31 -0
  20. fastapi_rebac-0.1.0a1/fastapi_rebac/anomaly/feature_builder.py +261 -0
  21. fastapi_rebac-0.1.0a1/fastapi_rebac/anomaly/pyod_detector.py +144 -0
  22. fastapi_rebac-0.1.0a1/fastapi_rebac/anomaly/rules.py +218 -0
  23. fastapi_rebac-0.1.0a1/fastapi_rebac/anomaly/service.py +235 -0
  24. fastapi_rebac-0.1.0a1/fastapi_rebac/auth.py +125 -0
  25. fastapi_rebac-0.1.0a1/fastapi_rebac/csrf.py +86 -0
  26. fastapi_rebac-0.1.0a1/fastapi_rebac/db/__init__.py +10 -0
  27. fastapi_rebac-0.1.0a1/fastapi_rebac/db/adapters.py +51 -0
  28. fastapi_rebac-0.1.0a1/fastapi_rebac/db/base.py +45 -0
  29. fastapi_rebac-0.1.0a1/fastapi_rebac/enums.py +27 -0
  30. fastapi_rebac-0.1.0a1/fastapi_rebac/errors.py +7 -0
  31. fastapi_rebac-0.1.0a1/fastapi_rebac/fastapi_rebac.py +894 -0
  32. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/__init__.py +3 -0
  33. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/yandex_2fa/__init__.py +25 -0
  34. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/yandex_2fa/admin.py +226 -0
  35. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/yandex_2fa/config.py +26 -0
  36. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/yandex_2fa/models.py +55 -0
  37. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/yandex_2fa/router.py +228 -0
  38. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/yandex_2fa/schemas.py +39 -0
  39. fastapi_rebac-0.1.0a1/fastapi_rebac/integrations/yandex_2fa/service.py +352 -0
  40. fastapi_rebac-0.1.0a1/fastapi_rebac/managers/__init__.py +11 -0
  41. fastapi_rebac-0.1.0a1/fastapi_rebac/managers/access_manager.py +503 -0
  42. fastapi_rebac-0.1.0a1/fastapi_rebac/managers/audit_manager.py +208 -0
  43. fastapi_rebac-0.1.0a1/fastapi_rebac/managers/user_manager.py +149 -0
  44. fastapi_rebac-0.1.0a1/fastapi_rebac/models/__init__.py +20 -0
  45. fastapi_rebac-0.1.0a1/fastapi_rebac/models/audit_log.py +35 -0
  46. fastapi_rebac-0.1.0a1/fastapi_rebac/models/auth_table.py +33 -0
  47. fastapi_rebac-0.1.0a1/fastapi_rebac/models/group.py +46 -0
  48. fastapi_rebac-0.1.0a1/fastapi_rebac/models/group_membership.py +38 -0
  49. fastapi_rebac-0.1.0a1/fastapi_rebac/models/group_permission.py +48 -0
  50. fastapi_rebac-0.1.0a1/fastapi_rebac/models/suspicious_alert.py +66 -0
  51. fastapi_rebac-0.1.0a1/fastapi_rebac/models/user.py +137 -0
  52. fastapi_rebac-0.1.0a1/fastapi_rebac/models/user_permission.py +46 -0
  53. fastapi_rebac-0.1.0a1/fastapi_rebac/py.typed +0 -0
  54. fastapi_rebac-0.1.0a1/fastapi_rebac/schemas.py +248 -0
  55. fastapi_rebac-0.1.0a1/fastapi_rebac/static/rebac_admin/css/rebac_admin.css +813 -0
  56. fastapi_rebac-0.1.0a1/fastapi_rebac/static/rebac_admin/js/rebac_admin.js +189 -0
  57. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/auth_tables.html +41 -0
  58. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/base.html +85 -0
  59. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/group_delete.html +19 -0
  60. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/group_detail.html +211 -0
  61. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/group_form.html +30 -0
  62. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/groups.html +57 -0
  63. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/index.html +28 -0
  64. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/login.html +38 -0
  65. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/resource_delete.html +33 -0
  66. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/resource_detail.html +38 -0
  67. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/resource_form.html +75 -0
  68. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/resource_list.html +86 -0
  69. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/resources.html +36 -0
  70. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/user_create.html +82 -0
  71. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/user_delete.html +19 -0
  72. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/user_detail.html +228 -0
  73. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/user_edit.html +77 -0
  74. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/user_password.html +25 -0
  75. fastapi_rebac-0.1.0a1/fastapi_rebac/templates/rebac_admin/users.html +71 -0
  76. fastapi_rebac-0.1.0a1/fastapi_rebac/types.py +230 -0
  77. fastapi_rebac-0.1.0a1/fastapi_rebac.egg-info/PKG-INFO +398 -0
  78. fastapi_rebac-0.1.0a1/fastapi_rebac.egg-info/SOURCES.txt +81 -0
  79. fastapi_rebac-0.1.0a1/fastapi_rebac.egg-info/dependency_links.txt +1 -0
  80. fastapi_rebac-0.1.0a1/fastapi_rebac.egg-info/requires.txt +52 -0
  81. fastapi_rebac-0.1.0a1/fastapi_rebac.egg-info/top_level.txt +1 -0
  82. fastapi_rebac-0.1.0a1/pyproject.toml +144 -0
  83. fastapi_rebac-0.1.0a1/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ldokov Roman
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,398 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastapi-rebac
3
+ Version: 0.1.0a1
4
+ Summary: RBAC/ReBAC authorization helpers, audit logging, suspicious activity detection, and admin UI for FastAPI applications.
5
+ Author-email: Ldokov Roman <ldokovroma@gmail.com>
6
+ Maintainer-email: Ldokov Roman <ldokovroma@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/lra-itsolution/fastapi-rebac/
9
+ Project-URL: Repository, https://github.com/lra-itsolution/fastapi-rebac/
10
+ Project-URL: Issues, https://github.com/lra-itsolution/fastapi-rebac/issues
11
+ Project-URL: Changelog, https://github.com/lra-itsolution/fastapi-rebac/blob/main/CHANGELOG.md
12
+ Keywords: fastapi,fastapi-users,sqlalchemy,rbac,rebac,authorization,access-control,audit-log,security
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Web Environment
15
+ Classifier: Framework :: AsyncIO
16
+ Classifier: Framework :: FastAPI
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: Internet :: WWW/HTTP
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
26
+ Classifier: Topic :: Security
27
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.10
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENSE
32
+ Requires-Dist: fastapi<1.0,>=0.110
33
+ Requires-Dist: fastapi-users[sqlalchemy]<16.0,>=14.0
34
+ Requires-Dist: SQLAlchemy<3.0,>=2.0
35
+ Requires-Dist: pydantic<3.0,>=2.0
36
+ Requires-Dist: jinja2<4.0,>=3.1
37
+ Requires-Dist: python-multipart<1.0,>=0.0.9
38
+ Requires-Dist: email-validator<3.0,>=2.0
39
+ Requires-Dist: greenlet<4.0,>=3.0
40
+ Provides-Extra: anomaly
41
+ Requires-Dist: pyod<4.0,>=2.0; extra == "anomaly"
42
+ Provides-Extra: postgres
43
+ Requires-Dist: asyncpg<1.0,>=0.29; extra == "postgres"
44
+ Requires-Dist: alembic<2.0,>=1.13; extra == "postgres"
45
+ Provides-Extra: yandex
46
+ Requires-Dist: httpx<1.0,>=0.27; extra == "yandex"
47
+ Provides-Extra: example
48
+ Requires-Dist: asyncpg<1.0,>=0.29; extra == "example"
49
+ Requires-Dist: alembic<2.0,>=1.13; extra == "example"
50
+ Requires-Dist: python-dotenv<2.0,>=1.0; extra == "example"
51
+ Requires-Dist: uvicorn[standard]<1.0,>=0.27; extra == "example"
52
+ Provides-Extra: test
53
+ Requires-Dist: pytest<9.0,>=8.0; extra == "test"
54
+ Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == "test"
55
+ Requires-Dist: httpx<1.0,>=0.27; extra == "test"
56
+ Provides-Extra: lint
57
+ Requires-Dist: ruff<1.0,>=0.6; extra == "lint"
58
+ Requires-Dist: mypy<2.0,>=1.8; extra == "lint"
59
+ Provides-Extra: release
60
+ Requires-Dist: build<2.0,>=1.2; extra == "release"
61
+ Requires-Dist: twine<7.0,>=5.0; extra == "release"
62
+ Provides-Extra: dev
63
+ Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
64
+ Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == "dev"
65
+ Requires-Dist: httpx<1.0,>=0.27; extra == "dev"
66
+ Requires-Dist: ruff<1.0,>=0.6; extra == "dev"
67
+ Requires-Dist: mypy<2.0,>=1.8; extra == "dev"
68
+ Requires-Dist: build<2.0,>=1.2; extra == "dev"
69
+ Requires-Dist: twine<7.0,>=5.0; extra == "dev"
70
+ Provides-Extra: all
71
+ Requires-Dist: asyncpg<1.0,>=0.29; extra == "all"
72
+ Requires-Dist: alembic<2.0,>=1.13; extra == "all"
73
+ Requires-Dist: httpx<1.0,>=0.27; extra == "all"
74
+ Requires-Dist: pyod<4.0,>=2.0; extra == "all"
75
+ Dynamic: license-file
76
+
77
+ # fastapi-rebac
78
+
79
+ `fastapi-rebac` is an alpha-stage FastAPI extension for relationship-based and role-aware access control. It combines FastAPI dependencies, FastAPI Users authentication, SQLAlchemy 2.0 models, a bundled HTML admin panel, audit logging, optional suspicious-activity detection, and optional Yandex ID two-factor authentication.
80
+
81
+ The library is designed for applications where access cannot be described by simple roles only. It supports direct user permissions, group permissions, user hierarchies, object-level checks, and SQLAlchemy query filtering for objects visible to the current user.
82
+
83
+ > Status: alpha. The public API is usable, but database schema and integration APIs may still change before a stable `1.0` release.
84
+
85
+ ## Features
86
+
87
+ - FastAPI dependency helpers for authenticated users, staff users, superusers, table-level permissions, object-level permissions, and accessible SQLAlchemy `select()` statements.
88
+ - SQLAlchemy 2.0 models for users, groups, group membership, registered protected tables, user permissions, group permissions, audit logs, and suspicious alerts.
89
+ - Integration layer around FastAPI Users for JWT bearer and cookie authentication backends.
90
+ - Relationship-aware visibility based on `created_by_id`, `supervisor_id`, and configurable group visibility flags.
91
+ - Bundled admin UI for users, groups, permissions, registered tables, audit logs, and suspicious alerts.
92
+ - Optional audit logging for security-relevant operations.
93
+ - Optional suspicious-activity detection with rule-based checks and PyOD ECOD outlier detection.
94
+ - Optional Yandex ID second-factor integration for API login and admin login flows.
95
+
96
+ ## Installation
97
+
98
+ Core package:
99
+
100
+ ```bash
101
+ pip install fastapi-rebac
102
+ ```
103
+
104
+ PostgreSQL and Alembic support for production-style applications:
105
+
106
+ ```bash
107
+ pip install "fastapi-rebac[postgres]"
108
+ ```
109
+
110
+ Optional suspicious-activity detection:
111
+
112
+ ```bash
113
+ pip install "fastapi-rebac[anomaly]"
114
+ ```
115
+
116
+ Optional Yandex ID two-factor authentication:
117
+
118
+ ```bash
119
+ pip install "fastapi-rebac[yandex]"
120
+ ```
121
+
122
+ Everything optional:
123
+
124
+ ```bash
125
+ pip install "fastapi-rebac[all]"
126
+ ```
127
+
128
+ ## Requirements
129
+
130
+ - Python 3.10+
131
+ - FastAPI
132
+ - FastAPI Users with SQLAlchemy support
133
+ - SQLAlchemy 2.0+
134
+ - Pydantic 2+
135
+ - Jinja2 and `python-multipart` for the bundled admin UI
136
+
137
+ The package is database-driver agnostic. Install a driver that matches your application database, for example `asyncpg` for PostgreSQL.
138
+
139
+ ## Quick start
140
+
141
+ The example below shows the minimal integration shape. Real applications should keep configuration values in environment variables and create Alembic migrations for the ReBAC tables.
142
+
143
+ ```python
144
+ from collections.abc import AsyncGenerator
145
+
146
+ from fastapi import Depends, FastAPI
147
+ from fastapi_users.db import SQLAlchemyUserDatabase
148
+ from sqlalchemy.ext.asyncio import AsyncSession
149
+
150
+ from fastapi_rebac import Action, FastAPIReBAC
151
+ from fastapi_rebac.auth import build_bearer_backend, build_get_user_manager
152
+ from fastapi_rebac.managers import ReBACUserManager
153
+ from fastapi_rebac.models import User
154
+
155
+ app = FastAPI()
156
+
157
+ async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
158
+ # yield your SQLAlchemy AsyncSession here
159
+ ...
160
+
161
+ async def get_user_db(
162
+ session: AsyncSession = Depends(get_async_session),
163
+ ) -> AsyncGenerator[SQLAlchemyUserDatabase[User, str], None]:
164
+ yield SQLAlchemyUserDatabase(session, User)
165
+
166
+ class UserManager(ReBACUserManager[User]):
167
+ reset_password_token_secret = "change-me"
168
+ verification_token_secret = "change-me"
169
+
170
+ get_user_manager = build_get_user_manager(UserManager, get_user_db)
171
+ auth_backend = build_bearer_backend(secret="change-me")
172
+
173
+ rebac = FastAPIReBAC(
174
+ get_user_manager,
175
+ [auth_backend],
176
+ get_async_session=get_async_session,
177
+ )
178
+
179
+ app.include_router(rebac.get_auth_router(), prefix="/auth/jwt", tags=["auth"])
180
+ rebac.mount_admin(app, prefix="/admin")
181
+
182
+ @app.get("/protected")
183
+ async def protected_route(user: User = Depends(rebac.auth_required)):
184
+ return {"user_id": str(user.id)}
185
+
186
+ @app.post("/notes", dependencies=[Depends(rebac.require(Action.CREATE, "note"))])
187
+ async def create_note():
188
+ return {"status": "allowed"}
189
+ ```
190
+
191
+ ## Registering protected entities
192
+
193
+ `fastapi-rebac` stores protected entities in the `auth_table` table. Registered models are synchronized through the `FastAPIReBAC.sync_auth_tables()` helper.
194
+
195
+ ```python
196
+ from sqlalchemy.ext.asyncio import AsyncSession
197
+
198
+ from my_app.models import Note
199
+
200
+ rebac.register_admin_model(
201
+ Note,
202
+ title="Notes",
203
+ user_ref_attr=Note.created_by_id,
204
+ )
205
+
206
+ async def sync_rebac_tables(session: AsyncSession) -> None:
207
+ await rebac.sync_auth_tables(session)
208
+ ```
209
+
210
+ After synchronization, administrators can grant `CREATE`, `READ`, `UPDATE`, and `DELETE` permissions for the registered entity.
211
+
212
+ ## Object-level access
213
+
214
+ For owned resources, pass a SQLAlchemy mapped user reference attribute. The access manager will build SQL that restricts data to the current user's visible user graph.
215
+
216
+ ```python
217
+ from fastapi import Depends
218
+ from sqlalchemy import select
219
+ from sqlalchemy.ext.asyncio import AsyncSession
220
+
221
+ from fastapi_rebac import Action
222
+ from my_app.models import Note
223
+
224
+ @app.get("/notes")
225
+ async def list_notes(
226
+ stmt = Depends(rebac.accessible_select(Note.created_by_id)),
227
+ session: AsyncSession = Depends(rebac.session_dependency),
228
+ ):
229
+ result = await session.execute(stmt.order_by(Note.created_at.desc()))
230
+ return result.scalars().all()
231
+
232
+ @app.get("/notes/{note_id}")
233
+ async def get_note(
234
+ note = Depends(rebac.require_object(Action.READ, Note.created_by_id, object_id_param="note_id")),
235
+ ):
236
+ return note
237
+ ```
238
+
239
+ ## Admin UI
240
+
241
+ The bundled admin UI is mounted on a FastAPI app with:
242
+
243
+ ```python
244
+ rebac.mount_admin(app, prefix="/admin")
245
+ ```
246
+
247
+ It includes pages for:
248
+
249
+ - users;
250
+ - groups and memberships;
251
+ - protected tables;
252
+ - user permissions;
253
+ - group permissions;
254
+ - audit logs;
255
+ - suspicious alerts.
256
+
257
+ The UI uses package templates and static assets from `fastapi_rebac/templates` and `fastapi_rebac/static`, so keep package data enabled when building distributions.
258
+
259
+ ## Audit logging
260
+
261
+ Audit logging is enabled by default in `FastAPIReBAC`. Use the audit manager when application code performs security-relevant actions:
262
+
263
+ ```python
264
+ audit = rebac.get_audit_manager(session)
265
+ await audit.log_success(
266
+ actor_id=user.id,
267
+ action=Action.UPDATE,
268
+ table_key="note",
269
+ object_id=str(note.id),
270
+ )
271
+ ```
272
+
273
+ Audit events can be used for incident analysis and for suspicious-activity detection.
274
+
275
+ ## Suspicious-activity detection
276
+
277
+ Install the optional extra:
278
+
279
+ ```bash
280
+ pip install "fastapi-rebac[anomaly]"
281
+ ```
282
+
283
+ Configure detection:
284
+
285
+ ```python
286
+ from fastapi_rebac import FastAPIReBAC
287
+ from fastapi_rebac.anomaly import SuspiciousActivityConfig
288
+
289
+ rebac = FastAPIReBAC(
290
+ get_user_manager,
291
+ [auth_backend],
292
+ get_async_session=get_async_session,
293
+ suspicious_activity_config=SuspiciousActivityConfig(
294
+ enabled=True,
295
+ rules_enabled=True,
296
+ pyod_enabled=True,
297
+ window_minutes=60,
298
+ ),
299
+ )
300
+ ```
301
+
302
+ Run detection manually or from the admin UI:
303
+
304
+ ```python
305
+ from fastapi_rebac.anomaly import run_suspicious_activity_detection
306
+
307
+ alerts = await run_suspicious_activity_detection(
308
+ session,
309
+ config=rebac.suspicious_activity_config,
310
+ )
311
+ ```
312
+
313
+ Rule-based detection works without PyOD. PyOD is imported lazily and is required only when `pyod_enabled=True`.
314
+
315
+ ## Yandex ID two-factor authentication
316
+
317
+ Install the optional extra:
318
+
319
+ ```bash
320
+ pip install "fastapi-rebac[yandex]"
321
+ ```
322
+
323
+ Then include the Yandex 2FA router instead of exposing a direct login route for users that must pass the second factor:
324
+
325
+ ```python
326
+ from fastapi_rebac.integrations.yandex_2fa import Yandex2FAConfig, get_yandex_2fa_router
327
+
328
+ config = Yandex2FAConfig(
329
+ client_id="...",
330
+ client_secret="...",
331
+ redirect_uri="http://127.0.0.1:8000/auth/yandex-2fa/callback",
332
+ link_redirect_uri="http://127.0.0.1:8000/auth/yandex-2fa/link/callback",
333
+ )
334
+
335
+ app.include_router(
336
+ get_yandex_2fa_router(rebac, config),
337
+ prefix="/auth/yandex-2fa",
338
+ tags=["auth"],
339
+ )
340
+ ```
341
+
342
+ Do not expose a separate direct JWT login route for accounts that must use Yandex 2FA; otherwise the second factor can be bypassed.
343
+
344
+ ## Examples
345
+
346
+ The repository contains two runnable examples:
347
+
348
+ - `example_app` — PostgreSQL example with JWT authentication, notes, admin UI, Alembic migrations, audit, and suspicious alerts.
349
+ - `example_yandex_2fa_app` — Yandex ID two-factor authentication example.
350
+
351
+ Typical local setup:
352
+
353
+ ```bash
354
+ python -m venv .venv
355
+ source .venv/bin/activate
356
+ python -m pip install --upgrade pip
357
+ pip install -e ".[example,anomaly,yandex]"
358
+ ```
359
+
360
+ Then follow the README inside the selected example directory.
361
+
362
+ ## Building and publishing
363
+
364
+ Build locally:
365
+
366
+ ```bash
367
+ python -m pip install --upgrade build twine
368
+ python -m build
369
+ python -m twine check dist/*
370
+ ```
371
+
372
+ Publish to TestPyPI:
373
+
374
+ ```bash
375
+ python -m twine upload --repository testpypi dist/*
376
+ ```
377
+
378
+ Publish to PyPI:
379
+
380
+ ```bash
381
+ python -m twine upload dist/*
382
+ ```
383
+
384
+ For GitHub Actions, prefer PyPI Trusted Publishing and the included `publish.yml` workflow.
385
+
386
+ ## Development
387
+
388
+ ```bash
389
+ python -m pip install -e ".[dev,all]"
390
+ python -m ruff check .
391
+ python -m pytest
392
+ python -m build
393
+ python -m twine check dist/*
394
+ ```
395
+
396
+ ## License
397
+
398
+ MIT License. See [LICENSE](LICENSE).