simple-module-auth 0.0.40__tar.gz → 0.0.42__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 (31) hide show
  1. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/PKG-INFO +17 -9
  2. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/README.md +13 -5
  3. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/deps.py +8 -9
  4. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/package.json +5 -6
  5. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/pyproject.toml +4 -4
  6. simple_module_auth-0.0.42/tests/test_auth_permission_deprecation.py +13 -0
  7. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/.gitignore +0 -0
  8. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/LICENSE +0 -0
  9. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/__init__.py +0 -0
  10. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/_route_match.py +0 -0
  11. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/contracts/__init__.py +0 -0
  12. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/contracts/provider.py +0 -0
  13. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/contracts/resolver.py +0 -0
  14. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/contracts/schemas.py +0 -0
  15. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/contracts/tokens.py +0 -0
  16. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/locales/de.json +0 -0
  17. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/locales/en.json +0 -0
  18. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/locales/es.json +0 -0
  19. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/middleware.py +0 -0
  20. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/module.py +0 -0
  21. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/py.typed +0 -0
  22. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/auth/state.py +0 -0
  23. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_auth_middleware.py +0 -0
  24. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_auth_next_target.py +0 -0
  25. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_auth_parse_bearer.py +0 -0
  26. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_auth_provider_protocol.py +0 -0
  27. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_auth_unknown_paths.py +0 -0
  28. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_deps.py +0 -0
  29. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_module.py +0 -0
  30. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_resolver_registry.py +0 -0
  31. {simple_module_auth-0.0.40 → simple_module_auth-0.0.42}/tests/test_user_context.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: simple_module_auth
3
- Version: 0.0.40
3
+ Version: 0.0.42
4
4
  Summary: Session-cookie authentication primitives — middleware, login/logout, redirect helpers for simple_module
5
5
  Project-URL: Homepage, https://github.com/antosubash/simple_module_python
6
6
  Project-URL: Repository, https://github.com/antosubash/simple_module_python
@@ -22,14 +22,14 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
22
  Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.12
24
24
  Requires-Dist: itsdangerous<3,>=2.2
25
- Requires-Dist: simple-module-core==0.0.40
26
- Requires-Dist: simple-module-db==0.0.40
27
- Requires-Dist: simple-module-hosting==0.0.40
25
+ Requires-Dist: simple-module-core==0.0.42
26
+ Requires-Dist: simple-module-db==0.0.42
27
+ Requires-Dist: simple-module-hosting==0.0.42
28
28
  Description-Content-Type: text/markdown
29
29
 
30
30
  # simple_module_auth
31
31
 
32
- Pluggable authentication core for [simple_module](https://github.com/antosubash/simple_module_python) apps. Owns the stable public contracts every other module imports — `UserContext`, the `AuthProvider` protocol, the `PrincipalResolver` chain, and the `get_current_user` / `CurrentUser` / `require_permission` dependencies — plus the `AuthMiddleware` that resolves the current principal on every request.
32
+ Pluggable authentication core for [simple_module](https://github.com/antosubash/simple_module_python) apps. Owns the stable public contracts every other module imports — `UserContext`, the `AuthProvider` protocol, the `PrincipalResolver` chain, and the `get_current_user` / `CurrentUser` dependencies — plus the `AuthMiddleware` that resolves the current principal on every request.
33
33
 
34
34
  **Heads up:** for most apps you don't install this directly — an auth-provider module (`simple_module_users` for email+password, `simple_module_keycloak` for OIDC) pulls it in and registers itself on `app.state.auth.auth_provider`.
35
35
 
@@ -45,7 +45,7 @@ pip install simple_module_auth
45
45
  - `AuthProvider` protocol — the swappable-backend contract (`resolve_user`, `get_login_url`, `get_logout_url`, `is_bearer_request`); exactly one provider module registers an implementation on `app.state.auth.auth_provider`.
46
46
  - `PrincipalResolver` chain — async `(Request) -> UserContext | None` callables apps append to `app.state.auth.principal_resolvers` (e.g. PAT/bearer-token or API-key auth), consulted after the session path.
47
47
  - `AuthMiddleware` — delegates to the provider + resolver chain on every request and populates the request principal.
48
- - `get_current_user` / `CurrentUser` dependency and the `require_permission(*permissions)` dependency factory.
48
+ - `get_current_user` / `CurrentUser` dependency.
49
49
  - Anonymous-access is declared via the framework's method-aware `register_public_routes` hook (with the `SM_AUTH_PUBLIC_PATHS` host-level escape hatch).
50
50
 
51
51
  ## Usage
@@ -63,18 +63,26 @@ async def me(user: CurrentUser):
63
63
  return {"user_id": user.id, "email": user.email}
64
64
  ```
65
65
 
66
- Routes that need a specific permission use the `require_permission(...)` dependency factory:
66
+ Routes that need a specific permission use `RequiresPermission` from hosting:
67
67
 
68
68
  ```python
69
69
  from fastapi import Depends
70
70
 
71
- from auth.deps import require_permission
71
+ from simple_module_hosting.permissions import RequiresPermission
72
72
 
73
+ from .constants import PERM_PRODUCTS_CREATE
73
74
 
74
- @router.post("/", dependencies=[Depends(require_permission("products.create"))])
75
+
76
+ @router.post("/", dependencies=[Depends(RequiresPermission(PERM_PRODUCTS_CREATE))])
75
77
  async def create_product(): ...
76
78
  ```
77
79
 
80
+ `auth.deps.require_permission` is deprecated and will be removed in **0.1.0**
81
+ (#698). It retains its legacy any-of semantics, role-based admin bypass and cached
82
+ permission check. Migrate to `RequiresPermission(PERM_KEY)`; for several required
83
+ permissions, declare a dependency for each. Unlike the legacy helper,
84
+ `RequiresPermission` rechecks administrators demoted during the request.
85
+
78
86
  ## Depends on
79
87
 
80
88
  - `simple_module_core`, `simple_module_db`
@@ -1,6 +1,6 @@
1
1
  # simple_module_auth
2
2
 
3
- Pluggable authentication core for [simple_module](https://github.com/antosubash/simple_module_python) apps. Owns the stable public contracts every other module imports — `UserContext`, the `AuthProvider` protocol, the `PrincipalResolver` chain, and the `get_current_user` / `CurrentUser` / `require_permission` dependencies — plus the `AuthMiddleware` that resolves the current principal on every request.
3
+ Pluggable authentication core for [simple_module](https://github.com/antosubash/simple_module_python) apps. Owns the stable public contracts every other module imports — `UserContext`, the `AuthProvider` protocol, the `PrincipalResolver` chain, and the `get_current_user` / `CurrentUser` dependencies — plus the `AuthMiddleware` that resolves the current principal on every request.
4
4
 
5
5
  **Heads up:** for most apps you don't install this directly — an auth-provider module (`simple_module_users` for email+password, `simple_module_keycloak` for OIDC) pulls it in and registers itself on `app.state.auth.auth_provider`.
6
6
 
@@ -16,7 +16,7 @@ pip install simple_module_auth
16
16
  - `AuthProvider` protocol — the swappable-backend contract (`resolve_user`, `get_login_url`, `get_logout_url`, `is_bearer_request`); exactly one provider module registers an implementation on `app.state.auth.auth_provider`.
17
17
  - `PrincipalResolver` chain — async `(Request) -> UserContext | None` callables apps append to `app.state.auth.principal_resolvers` (e.g. PAT/bearer-token or API-key auth), consulted after the session path.
18
18
  - `AuthMiddleware` — delegates to the provider + resolver chain on every request and populates the request principal.
19
- - `get_current_user` / `CurrentUser` dependency and the `require_permission(*permissions)` dependency factory.
19
+ - `get_current_user` / `CurrentUser` dependency.
20
20
  - Anonymous-access is declared via the framework's method-aware `register_public_routes` hook (with the `SM_AUTH_PUBLIC_PATHS` host-level escape hatch).
21
21
 
22
22
  ## Usage
@@ -34,18 +34,26 @@ async def me(user: CurrentUser):
34
34
  return {"user_id": user.id, "email": user.email}
35
35
  ```
36
36
 
37
- Routes that need a specific permission use the `require_permission(...)` dependency factory:
37
+ Routes that need a specific permission use `RequiresPermission` from hosting:
38
38
 
39
39
  ```python
40
40
  from fastapi import Depends
41
41
 
42
- from auth.deps import require_permission
42
+ from simple_module_hosting.permissions import RequiresPermission
43
43
 
44
+ from .constants import PERM_PRODUCTS_CREATE
44
45
 
45
- @router.post("/", dependencies=[Depends(require_permission("products.create"))])
46
+
47
+ @router.post("/", dependencies=[Depends(RequiresPermission(PERM_PRODUCTS_CREATE))])
46
48
  async def create_product(): ...
47
49
  ```
48
50
 
51
+ `auth.deps.require_permission` is deprecated and will be removed in **0.1.0**
52
+ (#698). It retains its legacy any-of semantics, role-based admin bypass and cached
53
+ permission check. Migrate to `RequiresPermission(PERM_KEY)`; for several required
54
+ permissions, declare a dependency for each. Unlike the legacy helper,
55
+ `RequiresPermission` rechecks administrators demoted during the request.
56
+
49
57
  ## Depends on
50
58
 
51
59
  - `simple_module_core`, `simple_module_db`
@@ -5,15 +5,14 @@ from __future__ import annotations
5
5
  from typing import Annotated
6
6
 
7
7
  from fastapi import Depends, HTTPException, Request
8
- from simple_module_core.permissions import grants
8
+ from simple_module_core.deprecation import deprecated
9
+ from simple_module_core.permissions import ADMIN_ROLE, grants
9
10
  from simple_module_hosting.i18n_deps import TranslatorDep
10
11
  from simple_module_hosting.permissions import ensure_resolved_permissions
11
12
  from simple_module_hosting.token_guard import GATE_PERMISSION, mark_token_gate
12
13
 
13
14
  from auth.contracts.schemas import UserContext
14
15
 
15
- _ADMIN_ROLE = "admin"
16
-
17
16
 
18
17
  async def get_current_user(request: Request, t: TranslatorDep) -> UserContext:
19
18
  """Extract the authenticated user from request state.
@@ -29,13 +28,13 @@ async def get_current_user(request: Request, t: TranslatorDep) -> UserContext:
29
28
  CurrentUser = Annotated[UserContext, Depends(get_current_user)]
30
29
 
31
30
 
31
+ @deprecated(remove_in="0.1.0", use="simple_module_hosting.permissions.RequiresPermission")
32
32
  def require_permission(*permissions: str):
33
- """Create a dependency that checks if the user has required permissions.
34
-
35
- Usage::
33
+ """Legacy any-of gate, removed in 0.1.0; use ``RequiresPermission`` instead.
36
34
 
37
- @router.post("/", dependencies=[Depends(require_permission("products.create"))])
38
- async def create_product(...): ...
35
+ Retains the role-based admin bypass and cached permission behaviour for
36
+ compatibility. ``RequiresPermission`` rechecks a principal demoted during
37
+ the request; this helper does not.
39
38
  """
40
39
 
41
40
  async def check(
@@ -46,7 +45,7 @@ def require_permission(*permissions: str):
46
45
  # Admin role bypasses permission checks — but not for a token: an
47
46
  # admin's PAT is worth only the scopes it carries, and the resolved
48
47
  # set below already applies that cap.
49
- if _ADMIN_ROLE in user.roles and user.scopes is None:
48
+ if ADMIN_ROLE in user.roles and user.scopes is None:
50
49
  return
51
50
 
52
51
  # The same resolution RequiresPermission reads: the registry's role map
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "@simple-module-py/auth",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "private": true,
5
5
  "description": "Frontend assets for the Auth module",
6
6
  "peerDependencies": {
7
+ "@inertiajs/react": "^3.9.1",
8
+ "@simple-module-py/ui": "*",
7
9
  "react": "^19.0.0",
8
- "react-dom": "^19.0.0",
9
- "@inertiajs/react": "^3.7.0",
10
- "@simple-module-py/ui": "*"
10
+ "react-dom": "^19.3.1"
11
11
  },
12
12
  "devDependencies": {
13
13
  "@simple-module-py/tsconfig": "*"
14
- },
15
- "dependencies": {}
14
+ }
16
15
  }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "simple_module_auth"
3
- version = "0.0.40"
3
+ version = "0.0.42"
4
4
  description = "Session-cookie authentication primitives — middleware, login/logout, redirect helpers for simple_module"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -22,9 +22,9 @@ classifiers = [
22
22
  ]
23
23
  dependencies = [
24
24
  "itsdangerous>=2.2,<3",
25
- "simple_module_core==0.0.40",
26
- "simple_module_db==0.0.40",
27
- "simple_module_hosting==0.0.40",
25
+ "simple_module_core==0.0.42",
26
+ "simple_module_db==0.0.42",
27
+ "simple_module_hosting==0.0.42",
28
28
  ]
29
29
 
30
30
  [project.entry-points.simple_module]
@@ -0,0 +1,13 @@
1
+ """The legacy any-of permission helper carries a migration warning (#698)."""
2
+
3
+ import pytest
4
+ from auth.deps import require_permission
5
+ from simple_module_core.deprecation import registered_deprecations
6
+
7
+
8
+ def test_auth_require_permission_warns_and_registers_removal():
9
+ with pytest.warns(DeprecationWarning, match="RequiresPermission"):
10
+ dependency = require_permission("products.view")
11
+ assert callable(dependency.dependency)
12
+ entry = next(d for d in registered_deprecations() if d.name == "auth.deps.require_permission")
13
+ assert entry.remove_in == "0.1.0"