- PyJWT defaults verify_aud and verify_iss to True, which rejects tokens
with iss/aud claims when no expected value is passed. Now explicitly
disables these checks when audience/issuer are not provided.
- Data vault get/delete now only suppress key-not-found errors
(DATA_VAULT_STORE_HASHED_KEY_DOES_NOT_EXIST), letting store-not-found
errors (DATA_VAULT_STORE_DOES_NOT_EXIST) propagate as they should.
The spec states "No error if key doesn't exist" but delete() was letting
404 responses bubble up as NotFoundError. Now mirrors the get() pattern
by catching NotFoundError silently, for both sync and async variants.
- Fix incorrect docstring method names in get_item (set_quantity ->
increase_quantity, decrease_quantity, try_decrease_quantity)
- Add asyncio.Lock to AsyncJWKSFetcher._fetch_jwks to deduplicate
concurrent JWKS fetches on cold/expired cache
- Add threading.Lock to SyncJWKSFetcher._fetch_jwks for same reason
- Add threading.Lock to _get_or_create_memory_store to prevent
race condition in token store registry
- Fix README clone URL to point to upstream repo
- Fix E2E test SyncJWKSFetcher constructor to use correct signature
(jwks_url + http_client instead of project_id + base_url)
Covers installation, quick start, async usage, authentication with
FastAPI example, error handling, teams, self-hosted config, full API
reference, and development/testing instructions.
Covers user CRUD lifecycle, team management, sessions, API key management,
authenticate_request with real request shapes, and async variants.
Requires STACK_E2E=1 env var and running Stack Auth instance.
- _decode_jwt_payload catches only ValueError and json.JSONDecodeError
- Token refresh catches httpx.HTTPError, ValueError, KeyError with debug log
- authenticate_request catches jwt.PyJWTError, httpx.HTTPError, ValueError, KeyError
- Added docstring to _token_store_registry explaining purpose and test reset
- Updated test mocks to use jwt.PyJWTError instead of bare Exception
- Add @runtime_checkable decorator to RequestLike Protocol
- Replace bare fallback with isinstance(init, RequestLike) check in resolve_token_store
- Raise TypeError for invalid token store initializer types
- Add tests for isinstance checks and invalid input handling
- Decode JWT access token claims locally without network request
- Return TokenPartialUser with user ID, display name, email, and flags
- Return None when no token store or no access token available
- Support token_store override parameter for per-call flexibility
- Method is synchronous on both classes since it performs no I/O
- Test get_partial_user returns TokenPartialUser from valid JWT
- Test returns None when no token store, explicit None, or empty store
- Test token_store override parameter
- Test async variant works identically (sync method, no I/O)
- Add publishable_client_key param to BaseAPIClient, StackServerApp, AsyncStackServerApp
- Include x-stack-publishable-client-key header when key is provided
- Change ExplicitTokenStore defaults from empty string to None
- Remove empty string fallback in resolve_token_store dict branch
- Test publishable_client_key header included/omitted in _build_headers
- Test ExplicitTokenStore defaults to None without arguments
- Test resolve_token_store dict branch defaults missing keys to None
- Test StackServerApp/AsyncStackServerApp accept publishable_client_key
The Stack Auth API returns null for client_metadata, client_read_only_metadata,
and server_metadata when not set, but the models expected dict. Changed to
dict | None to handle null responses gracefully.
- Add Args, Returns, and Raises sections to all public methods on
StackServerApp and AsyncStackServerApp (~46 methods each)
- Expand class-level docstrings with full constructor and usage examples
- Document return-None-on-404 behavior, ValueError raises, and error types
- Add _resolve_customer_path helper for polymorphic customer identification
- Add list_products, get_item, grant_product, cancel_subscription to both sync and async facades
- Add send_email and get_email_delivery_stats to both sync and async facades
- Export ServerItem, AsyncServerItem, EmailDeliveryInfo from package root
- ServerItem wraps Item with increase/decrease/tryDecrease quantity methods
- AsyncServerItem provides async counterpart for quantity operations
- EmailDeliveryInfo model for delivery statistics (delivered/bounced/complained/total)
- Export new models from models package
- create_oauth_provider links OAuth provider to a user
- list_oauth_providers and get_oauth_provider for provider lookup
- list_connected_accounts as alias for list_oauth_providers
- Sync and async versions on both facade classes with tests
- User API key create/list/revoke on StackServerApp and AsyncStackServerApp
- Team API key create/list/revoke on both facades
- check_api_key validates any key and returns user_id/team_id
- Tests for all sync and async API key methods
- list_contact_channels, create_contact_channel for user channels
- send_verification_code with optional callback URL
- verify_contact_channel to validate codes
- Both sync and async facades
- Tests for list, create, send verification, verify on sync facade
- Tests for all contact channel methods on async facade
- Covers optional fields and callback URL parameter
- grant_permission, revoke_permission for team and project scope
- list_permissions with optional direct filter
- has_permission boolean check, get_permission single lookup
- Both sync and async facades
- Tests for grant, revoke, list, has, get permission on sync facade
- Tests for all permission methods on async facade
- Covers team-scoped and project-level permissions
- Add add_team_member and remove_team_member via /team-memberships
- Add send_team_invitation, list_team_invitations, revoke_team_invitation
- Add list_team_member_profiles and get_team_member_profile
- Add user_id field to TeamMemberProfile for profile filtering
- Both sync and async facades have identical method surfaces
- Tests for add_team_member, remove_team_member
- Tests for send/list/revoke team invitations
- Tests for list_team_member_profiles and get_team_member_profile
- Async equivalents for all membership/invitation/profile operations
- Tests for get_team, list_teams, create_team, update_team, delete_team
- Tests for get_team_by_api_key two-step lookup
- Async equivalents for all team CRUD operations
- Uses respx mocking pattern consistent with existing user tests
- list_sessions(user_id) returns list of ActiveSession for a user
- get_session(session_id, user_id) filters from list_sessions, returns ActiveSession or None
- revoke_session(session_id, user_id) deletes session via DELETE endpoint
- Both sync and async facades implement all three methods
- StackServerApp (sync) and AsyncStackServerApp (async) facade classes
- get_user returns ServerUser or None on 404
- list_users with cursor/limit/order_by/desc/query/include_restricted/include_anonymous
- create_user sends only non-None fields
- update_user uses _UNSET sentinel to distinguish not-provided from explicit None
- delete_user returns None
- get_user_by_api_key performs two-step lookup via /api-keys/check then /users/{id}
- Both classes support context managers and compose API client + optional token store
- Tests for get_user, list_users, create_user, update_user, delete_user
- Tests for get_user_by_api_key two-step lookup
- Tests for sentinel pattern in update_user (None vs not-provided)
- Both sync and async facades covered with respx mocks
- TokenStore ABC with get_stored_access_token, get_stored_refresh_token, compare_and_set
- MemoryTokenStore, ExplicitTokenStore, RequestTokenStore implementations
- Module-level registry shares MemoryTokenStore instances per project_id
- resolve_token_store handles memory/dict/request/None init variants
- CAS refresh algorithm (sync + async) with 20s expiry buffer and 75s iat threshold
- Token refresh via form-encoded POST to /api/v1/auth/oauth/token
- Per-instance threading.Lock and asyncio.Lock for concurrency safety
- 34 passing tests covering all store types, registry, helpers, and CAS branches
- Add AuthState, TokenPartialUser, decode_access_token_claims to public API
- Add sync_authenticate_request and async_authenticate_request exports
- Existing exports unchanged
- TokenPartialUser frozen dataclass for unverified JWT payload extraction
- AuthState frozen dataclass for authentication results
- decode_access_token_claims extracts user info without signature verification
- _extract_token_from_headers handles Authorization and x-stack-auth headers
- sync_authenticate_request and async_authenticate_request compose with JWKS verifier
- PaginatedResult[T] generic wrapping nested {items, pagination: {next_cursor}} shape
- Convenience properties .next_cursor and .has_next_page
- Package __init__.py exports all models, errors, and PaginatedResult
- SyncAPIClient/AsyncAPIClient intentionally excluded from public API
- Tests verify pagination with ServerUser and Team types
- BaseAPIClient generic base with header construction, URL building,
response parsing via x-stack-actual-status and x-stack-known-error
- SyncAPIClient wrapping httpx.Client with context manager support
- AsyncAPIClient wrapping httpx.AsyncClient with async context manager
- Exponential backoff retry for idempotent methods (GET/PUT/DELETE)
- 429 rate limit handling with Retry-After header support
- POST/PUT/PATCH with no body sends {} as JSON
- All 26 tests passing
- BaseUser and ServerUser with camelCase aliases and millis-to-datetime properties
- Team, ServerTeam, TeamMemberProfile, TeamInvitation with timestamp conversions
- ActiveSession with GeoInfo nested model
- ContactChannel and TeamPermission/ProjectPermission
- Tests for user and team model parsing, inheritance, and field conversion
- StackAuthError base with code/message/details and from_response() factory
- 13 category subclasses: Authentication, NotFound, Validation, PermissionDenied,
Conflict, OAuth, Passkey, ApiKey, Payment, Email, RateLimit, Cli, Analytics
- Complete _ERROR_CODE_MAP with 143 error codes from known-errors.tsx
- StackAuthModel base class with Pydantic v2 ConfigDict and millis conversion
- Package exports via __init__.py with __all__
- Test StackAuthError base class storage and string representation
- Test all 13 category subclasses inherit from StackAuthError
- Test from_response() dispatch for known and unknown error codes
- Test StackAuthModel config and millis conversion
- Package skeleton with pyproject.toml (stubs only, tests expected to fail)