xn-auth 0.2.54__tar.gz → 0.2.56__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.
@@ -0,0 +1,55 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Overview
6
+
7
+ x-auth (`xn-auth` on PyPI) is a JWT cookie-based authentication middleware for Litestar (ASGI framework). It handles Telegram-based authentication via Mini Apps (TMA) and Login Widget (TWA), with automatic token refresh when expired.
8
+
9
+ ## Build & Publish
10
+
11
+ ```bash
12
+ # Install dependencies
13
+ pip install -e ".[dev]"
14
+
15
+ # Build package
16
+ python -m build
17
+
18
+ # Publish to PyPI
19
+ twine upload dist/*
20
+ ```
21
+
22
+ ## Architecture
23
+
24
+ ### Authentication Flow
25
+
26
+ 1. **Entry point**: `Auth` class in `controller.py` - initializes `JWTCookieAuth` from Litestar with custom middleware
27
+ 2. **Endpoints**: `/auth/tma` (Mini App initData) and `/auth/twa` (Login Widget) - both validate Telegram signatures and issue JWT tokens
28
+ 3. **Token handling**: Custom `Tok` class in `middleware.py` extends `Token` to catch `ExpiredSignatureError` and re-encode with fresh timestamps
29
+ 4. **Auto-refresh**: `JWTAuthMiddleware` intercepts expired tokens, checks if user is blocked via `User.permissions()`, updates role if changed, and sets new cookie
30
+
31
+ ### Key Components
32
+
33
+ - **`Auth`** (`controller.py`): Main class instantiated by consuming applications. Pass the Telegram bot token as `sec`, optionally a custom `User` model, excluded paths, and cookie domain.
34
+ - **`JWTAuthMiddleware`** (`middleware.py`): Wraps Litestar's `JWTCookieAuthenticationMiddleware`. On `ExpiredSignature`, fetches user permissions from DB and issues refreshed token via `Set-Cookie` header injection.
35
+ - **`User`** model (`models.py`): Tortoise ORM model with `tg_upsert()` for login and `permissions()` for token refresh checks. Related to `Username` for Telegram user ID mapping.
36
+ - **Role system** (`enums.py`): Bitmask-based roles (`READER=4`, `WRITER=2`, `MANAGER=6`, `ADMIN=7`) using `RoleScope` flags.
37
+
38
+ ### Token Contents
39
+
40
+ JWT extras stored beyond standard claims:
41
+ - `role`: User's current role (refreshed on token renewal)
42
+ - `blocked`: Whether user has blocked the bot (checked via `allows_write_to_pm` or `send_chat_action`)
43
+
44
+ ### Dependencies
45
+
46
+ - `litestar` - ASGI framework (JWT auth support)
47
+ - `tortoise-orm` via `xn-model` - Database models
48
+ - `aiogram` - Telegram signature validation and bot API
49
+ - `kurigram` - Pyrogram fork for session/peer models
50
+ - `pyjwt` - JWT encoding/decoding
51
+ - `msgspec` - Fast serialization
52
+
53
+ ### Excluded Paths
54
+
55
+ Default paths excluded from auth: `/schema`, `/auth`, `/public`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xn-auth
3
- Version: 0.2.54
3
+ Version: 0.2.56
4
4
  Summary: Auth adapter for XN-Api framework
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
6
  License: MIT
@@ -22,6 +22,10 @@ Requires-Dist: twine; extra == "dev"
22
22
  # X-Auth
23
23
  ###### JWT authentication for x-api
24
24
 
25
+ JWT cookie based Auth Middleware for ASGI framework.
26
+ Stores in user_id, issued and expired dates, user role and blocked state.
27
+ When token expired, it is automatically fetching user from db, and if he is not blocked now, then updates issue/expire dates, and user role if it was changed after the last user fetch.
28
+
25
29
  #### Requirements
26
30
  - Python >= 3.12
27
31
 
@@ -0,0 +1,17 @@
1
+ # X-Auth
2
+ ###### JWT authentication for x-api
3
+
4
+ JWT cookie based Auth Middleware for ASGI framework.
5
+ Stores in user_id, issued and expired dates, user role and blocked state.
6
+ When token expired, it is automatically fetching user from db, and if he is not blocked now, then updates issue/expire dates, and user role if it was changed after the last user fetch.
7
+
8
+ #### Requirements
9
+ - Python >= 3.12
10
+
11
+ ### INSTALL
12
+ ```bash
13
+ pip install xn-auth
14
+ ```
15
+
16
+ ---
17
+ Made with ❤ on top of the [X-Model](https://github.com/XyncNet/x-model).
@@ -56,7 +56,8 @@ class Auth:
56
56
  {
57
57
  **user.model_dump(),
58
58
  "xid": db_user.id,
59
- "pub": db_user.pub and b64encode(db_user.pub),
59
+ "pub": b64encode(db_user.pub),
60
+ "prv": db_user.prv and b64encode(db_user.prv),
60
61
  "allows_write_to_pm": user.allows_write_to_pm or not db_user.blocked,
61
62
  }
62
63
  ),
@@ -0,0 +1,5 @@
1
+ from jwt import ExpiredSignatureError
2
+
3
+
4
+ class ExpiredSignature(Exception):
5
+ def __init__(self, uid: int, encoded_token: str, secret: str, _e: ExpiredSignatureError): ...
@@ -38,8 +38,8 @@ class Tok(Token):
38
38
  }
39
39
  )
40
40
  tok = convert(payload, cls, strict=False)
41
- encoded_token = tok.encode(secret, algorithms[0]) # check where from getting algorithms
42
- raise ExpiredSignature(int(payload["sub"]), encoded_token, e)
41
+ encoded_token = tok.encode(secret, algorithms[0])
42
+ raise ExpiredSignature(int(payload["sub"]), encoded_token, secret, e)
43
43
 
44
44
 
45
45
  class JWTAuthMiddleware(JWTCookieAuthenticationMiddleware):
@@ -47,10 +47,17 @@ class JWTAuthMiddleware(JWTCookieAuthenticationMiddleware):
47
47
  try:
48
48
  await super().__call__(scope, receive, send)
49
49
  except ExpiredSignature as e:
50
- uid, uet, _e = e.args # uid, updated encoded token
51
- if await scope["app"].state.get("user_model").is_blocked(uid):
50
+ uid, uet, secret, _e = e.args # uid, updated encoded token
51
+ blocked, role = await scope["app"].state.get("user_model").permissions(uid)
52
+ if blocked:
52
53
  logging.error(f"User#{uid} can't refresh. Blocked!")
53
54
  raise _e
55
+ payload = Tok.decode_payload(uet, secret, ["HS256"])
56
+ if role.value != payload["extras"]["role"]:
57
+ # update user role in jwtoken
58
+ payload["extras"]["role"] = role.value
59
+ tok = convert(payload, Tok, strict=False)
60
+ uet = tok.encode(secret, "HS256")
54
61
 
55
62
  async def send_wrapper(msg: Message) -> None:
56
63
  if msg["type"] == "http.response.start":
@@ -78,8 +78,9 @@ class User(Model):
78
78
  return user_dict
79
79
 
80
80
  @classmethod
81
- async def is_blocked(cls, sid: str) -> bool:
82
- return (await cls[int(sid)]).blocked
81
+ async def permissions(cls, self_id: str) -> tuple[bool, Role]:
82
+ user = await cls[self_id]
83
+ return user.blocked, user.role
83
84
 
84
85
  @classmethod
85
86
  async def tg_upsert(cls, u: PyroUser | AioUser | WebAppUser, blocked: bool = None) -> tuple["User", bool]:
@@ -68,4 +68,5 @@ class TgUser(Xs):
68
68
 
69
69
  class XyncUser(WebAppUser):
70
70
  xid: int
71
- pub: bytes | None
71
+ pub: bytes
72
+ prv: bytes | None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xn-auth
3
- Version: 0.2.54
3
+ Version: 0.2.56
4
4
  Summary: Auth adapter for XN-Api framework
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
6
  License: MIT
@@ -22,6 +22,10 @@ Requires-Dist: twine; extra == "dev"
22
22
  # X-Auth
23
23
  ###### JWT authentication for x-api
24
24
 
25
+ JWT cookie based Auth Middleware for ASGI framework.
26
+ Stores in user_id, issued and expired dates, user role and blocked state.
27
+ When token expired, it is automatically fetching user from db, and if he is not blocked now, then updates issue/expire dates, and user role if it was changed after the last user fetch.
28
+
25
29
  #### Requirements
26
30
  - Python >= 3.12
27
31
 
@@ -1,6 +1,7 @@
1
1
  .env.dist
2
2
  .gitignore
3
3
  .pre-commit-config.yaml
4
+ CLAUDE.md
4
5
  README.md
5
6
  makefile
6
7
  pyproject.toml
xn_auth-0.2.54/README.md DELETED
@@ -1,13 +0,0 @@
1
- # X-Auth
2
- ###### JWT authentication for x-api
3
-
4
- #### Requirements
5
- - Python >= 3.12
6
-
7
- ### INSTALL
8
- ```bash
9
- pip install xn-auth
10
- ```
11
-
12
- ---
13
- Made with ❤ on top of the [X-Model](https://github.com/XyncNet/x-model).
@@ -1,5 +0,0 @@
1
- from jwt import ExpiredSignatureError
2
-
3
-
4
- class ExpiredSignature(Exception):
5
- def __init__(self, _uid: int, _encoded_token: str, _e: ExpiredSignatureError): ...
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes