fix: use URL-safe base64 encoding for cursor tokens (#160)

This commit is contained in:
d3vyce
2026-03-21 15:33:17 +01:00
committed by GitHub
parent f0223ebde4
commit 768e405554
2 changed files with 12 additions and 7 deletions

View File

@@ -255,7 +255,7 @@ The cursor column is set once on [`CrudFactory`](../reference/crud.md#fastapi_to
!!! note
`cursor_column` is required. Calling [`cursor_paginate`](../reference/crud.md#fastapi_toolsets.crud.factory.AsyncCrud.cursor_paginate) on a CRUD class that has no `cursor_column` configured raises a `ValueError`.
The cursor value is base64-encoded when returned to the client and decoded back to the correct Python type on the next request. The following SQLAlchemy column types are supported:
The cursor value is URL-safe base64-encoded (no padding) when returned to the client and decoded back to the correct Python type on the next request. The following SQLAlchemy column types are supported:
| SQLAlchemy type | Python type |
|---|---|

View File

@@ -58,15 +58,20 @@ class _CursorDirection(str, Enum):
def _encode_cursor(
value: Any, *, direction: _CursorDirection = _CursorDirection.NEXT
) -> str:
"""Encode a cursor column value and navigation direction as a base64 string."""
return base64.b64encode(
"""Encode a cursor column value and navigation direction as a URL-safe base64 string."""
return (
base64.urlsafe_b64encode(
json.dumps({"val": str(value), "dir": direction}).encode()
).decode()
)
.decode()
.rstrip("=")
)
def _decode_cursor(cursor: str) -> tuple[str, _CursorDirection]:
"""Decode a cursor base64 string into ``(raw_value, direction)``."""
payload = json.loads(base64.b64decode(cursor.encode()).decode())
"""Decode a URL-safe base64 cursor string into ``(raw_value, direction)``."""
padded = cursor + "=" * (-len(cursor) % 4)
payload = json.loads(base64.urlsafe_b64decode(padded).decode())
return payload["val"], _CursorDirection(payload["dir"])