simple-module-auth 0.0.37__tar.gz → 0.0.38__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 (30) hide show
  1. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/.gitignore +1 -2
  2. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/PKG-INFO +4 -4
  3. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/README.md +1 -1
  4. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/contracts/provider.py +0 -2
  5. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/contracts/schemas.py +20 -7
  6. simple_module_auth-0.0.38/auth/locales/de.json +6 -0
  7. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/middleware.py +4 -3
  8. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/package.json +1 -1
  9. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/pyproject.toml +3 -3
  10. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/LICENSE +0 -0
  11. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/__init__.py +0 -0
  12. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/_route_match.py +0 -0
  13. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/contracts/__init__.py +0 -0
  14. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/contracts/resolver.py +0 -0
  15. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/contracts/tokens.py +0 -0
  16. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/deps.py +0 -0
  17. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/locales/en.json +0 -0
  18. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/locales/es.json +0 -0
  19. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/module.py +0 -0
  20. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/py.typed +0 -0
  21. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/auth/state.py +0 -0
  22. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_auth_middleware.py +0 -0
  23. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_auth_next_target.py +0 -0
  24. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_auth_parse_bearer.py +0 -0
  25. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_auth_provider_protocol.py +0 -0
  26. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_auth_unknown_paths.py +0 -0
  27. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_deps.py +0 -0
  28. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_module.py +0 -0
  29. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_resolver_registry.py +0 -0
  30. {simple_module_auth-0.0.37 → simple_module_auth-0.0.38}/tests/test_user_context.py +0 -0
@@ -7,8 +7,6 @@ build/
7
7
  .venv/
8
8
  *.egg
9
9
 
10
- # UV
11
- uv.lock
12
10
 
13
11
  # Node
14
12
  node_modules/
@@ -65,3 +63,4 @@ host/client_app/.playwright-cli/*
65
63
  .qa/
66
64
  .verify/
67
65
  /openapi.json
66
+ qa-shots/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: simple_module_auth
3
- Version: 0.0.37
3
+ Version: 0.0.38
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,8 +22,8 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
22
  Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.12
24
24
  Requires-Dist: itsdangerous>=2.2
25
- Requires-Dist: simple-module-core==0.0.37
26
- Requires-Dist: simple-module-db==0.0.37
25
+ Requires-Dist: simple-module-core==0.0.38
26
+ Requires-Dist: simple-module-db==0.0.38
27
27
  Description-Content-Type: text/markdown
28
28
 
29
29
  # simple_module_auth
@@ -41,7 +41,7 @@ pip install simple_module_auth
41
41
  ## What it provides
42
42
 
43
43
  - `UserContext` — the request-scoped principal (`id`, `name`, `email`, `roles`).
44
- - `AuthProvider` protocol — the swappable-backend contract (`resolve_user`, `get_login_url`, `get_logout_url`, `get_public_paths`, `is_bearer_request`); exactly one provider module registers an implementation on `app.state.auth.auth_provider`.
44
+ - `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`.
45
45
  - `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.
46
46
  - `AuthMiddleware` — delegates to the provider + resolver chain on every request and populates the request principal.
47
47
  - `get_current_user` / `CurrentUser` dependency and the `require_permission(*permissions)` dependency factory.
@@ -13,7 +13,7 @@ pip install simple_module_auth
13
13
  ## What it provides
14
14
 
15
15
  - `UserContext` — the request-scoped principal (`id`, `name`, `email`, `roles`).
16
- - `AuthProvider` protocol — the swappable-backend contract (`resolve_user`, `get_login_url`, `get_logout_url`, `get_public_paths`, `is_bearer_request`); exactly one provider module registers an implementation on `app.state.auth.auth_provider`.
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
19
  - `get_current_user` / `CurrentUser` dependency and the `require_permission(*permissions)` dependency factory.
@@ -26,8 +26,6 @@ class AuthProvider(Protocol):
26
26
 
27
27
  def get_logout_url(self, request: Request) -> str: ...
28
28
 
29
- def get_public_paths(self) -> tuple[tuple[str, ...], tuple[str, ...]]: ...
30
-
31
29
  def is_bearer_request(self, request: Request) -> bool: ...
32
30
 
33
31
 
@@ -2,15 +2,28 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from collections.abc import Iterable
5
6
  from dataclasses import dataclass, field
6
- from typing import TYPE_CHECKING, Any
7
+ from typing import Any, Protocol
7
8
 
8
9
  from auth.contracts.tokens import AUTH_KIND_SESSION
9
10
 
10
- if TYPE_CHECKING:
11
- # Runtime import would be circular: auth -> users -> auth.
12
- # Only imported for type-hints, never at runtime.
13
- from users.models import User
11
+
12
+ class NamedRole(Protocol):
13
+ name: str
14
+
15
+
16
+ class AccountLike(Protocol):
17
+ """What :meth:`UserContext.from_user` reads from an account row.
18
+
19
+ Structural, so ``auth`` names no provider's model: ``users`` depends on
20
+ ``auth``, never the other way round (GH #501).
21
+ """
22
+
23
+ id: Any
24
+ email: str
25
+ full_name: str | None
26
+ roles: Iterable[NamedRole]
14
27
 
15
28
 
16
29
  @dataclass
@@ -53,12 +66,12 @@ class UserContext:
53
66
  @classmethod
54
67
  def from_user(
55
68
  cls,
56
- user: User | Any,
69
+ user: AccountLike,
57
70
  *,
58
71
  auth_kind: str = AUTH_KIND_SESSION,
59
72
  scopes: list[str] | None = None,
60
73
  ) -> UserContext:
61
- """Build a UserContext from a users.models.User with eagerly-loaded roles.
74
+ """Build a UserContext from an :class:`AccountLike` with eagerly-loaded roles.
62
75
 
63
76
  Duck-typed to avoid importing users.models at runtime — any object
64
77
  exposing .id, .email, .full_name, .roles[*].name works. The user row
@@ -0,0 +1,6 @@
1
+ {
2
+ "errors": {
3
+ "not_authenticated": "Nicht authentifiziert",
4
+ "missing_permission": "Erforderliche Berechtigung fehlt: {permissions}"
5
+ }
6
+ }
@@ -10,6 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  import logging
12
12
 
13
+ from simple_module_core.public_routes import legacy_provider_public_paths
13
14
  from simple_module_core.redirect_safety import SESSION_NEXT_KEY, safe_next_or_none
14
15
  from simple_module_db.listeners import current_user_id
15
16
  from starlette.requests import Request
@@ -94,10 +95,10 @@ class AuthMiddleware:
94
95
  if not is_public:
95
96
  public_routes = getattr(app_state, "public_routes", None)
96
97
  is_public = public_routes is not None and public_routes.matches(method, path)
97
- # Legacy provider-declared paths (prefix-only, method-agnostic). Kept for
98
- # back-compat with AuthProvider implementations.
98
+ # Deprecated provider-declared paths (prefix-only, method-agnostic); honoured
99
+ # until 0.1.0 for third-party providers. users/keycloak use the registry.
99
100
  if not is_public:
100
- prefix_paths, exact_paths = provider.get_public_paths()
101
+ prefix_paths, exact_paths = legacy_provider_public_paths(provider)
101
102
  is_public = any(path.startswith(p) for p in prefix_paths) or path in exact_paths
102
103
 
103
104
  # Contract with the host's RateLimitMiddleware (plain scope key, no import
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-module-py/auth",
3
- "version": "0.1.0",
3
+ "version": "0.0.38",
4
4
  "private": true,
5
5
  "description": "Frontend assets for the Auth module",
6
6
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "simple_module_auth"
3
- version = "0.0.37"
3
+ version = "0.0.38"
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,8 +22,8 @@ classifiers = [
22
22
  ]
23
23
  dependencies = [
24
24
  "itsdangerous>=2.2",
25
- "simple_module_core==0.0.37",
26
- "simple_module_db==0.0.37",
25
+ "simple_module_core==0.0.38",
26
+ "simple_module_db==0.0.38",
27
27
  ]
28
28
 
29
29
  [project.entry-points.simple_module]