scalekit-sdk-python 2.16.0__tar.gz → 2.18.0__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.
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/PKG-INFO +91 -2
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/README.md +82 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/_version.py +1 -1
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/client.py +32 -9
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/core.py +90 -9
- scalekit_sdk_python-2.18.0/scalekit/frameworks/django.py +369 -0
- scalekit_sdk_python-2.18.0/scalekit/frameworks/fastapi.py +386 -0
- scalekit_sdk_python-2.18.0/scalekit/frameworks/flask.py +368 -0
- scalekit_sdk_python-2.18.0/scalekit/middleware/csrf_state.py +57 -0
- scalekit_sdk_python-2.18.0/scalekit/middleware/protocol.py +56 -0
- scalekit_sdk_python-2.18.0/scalekit/middleware/session_crypto.py +126 -0
- scalekit_sdk_python-2.18.0/scalekit/middleware/session_manager.py +242 -0
- scalekit_sdk_python-2.18.0/scalekit/v1/webhooks/__init__.py +0 -0
- scalekit_sdk_python-2.18.0/scalekit/v1/workspaces/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit_sdk_python.egg-info/PKG-INFO +91 -2
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit_sdk_python.egg-info/SOURCES.txt +17 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit_sdk_python.egg-info/requires.txt +10 -1
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/setup.py +9 -1
- scalekit_sdk_python-2.18.0/tests/test_http_timeout.py +59 -0
- scalekit_sdk_python-2.18.0/tests/test_keepalive_channel_options.py +87 -0
- scalekit_sdk_python-2.18.0/tests/test_middleware_csrf_state.py +47 -0
- scalekit_sdk_python-2.18.0/tests/test_middleware_django.py +428 -0
- scalekit_sdk_python-2.18.0/tests/test_middleware_fastapi.py +434 -0
- scalekit_sdk_python-2.18.0/tests/test_middleware_flask.py +557 -0
- scalekit_sdk_python-2.18.0/tests/test_middleware_session_crypto.py +86 -0
- scalekit_sdk_python-2.18.0/tests/test_middleware_session_manager.py +303 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/LICENSE +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/buf/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/buf/validate/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/buf/validate/validate_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/buf/validate/validate_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/buf/validate/validate_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/pyproject.toml +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/actions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/frameworks/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/frameworks/google_adk.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/frameworks/langchain.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/frameworks/types/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/frameworks/types/google_adk_tool.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/frameworks/util.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/custom_provider.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/mcp_config.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/mcp_connection_auth_state.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/mcp_instance.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/create_connected_account_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/create_custom_provider_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/delete_custom_provider_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/list_providers_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/mcp_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/tool_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/update_connected_account_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/requests/update_custom_provider_request.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/create_connected_account_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/create_custom_provider_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/create_mcp_config_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/create_mcp_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/create_mcp_session_token_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/delete_connected_account_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/delete_custom_provider_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/delete_mcp_config_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/delete_mcp_instance_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/ensure_mcp_instance_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/execute_tool_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/get_connected_account_auth_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/get_mcp_instance_auth_state_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/get_mcp_instance_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/get_mcp_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/list_connected_accounts_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/list_mcp_configs_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/list_mcp_connected_accounts_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/list_mcp_instances_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/list_providers_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/magic_link_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/update_connected_account_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/update_custom_provider_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/update_mcp_config_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/update_mcp_instance_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/responses/verify_connected_account_user_response.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/tool_input_output.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/models/tool_mapping.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/modifier.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/actions/types.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/auth.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/common/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/common/exceptions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/common/scalekit.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/common/user.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/connected_accounts.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/connection.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/constants/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/constants/user.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/directory.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/domain.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/events.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/utils → scalekit_sdk_python-2.18.0/scalekit/frameworks}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/m2m_client.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/mcp.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1 → scalekit_sdk_python-2.18.0/scalekit/middleware}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/organization.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/passwordless.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/permissions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/providers.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/role.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/sessions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/token.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/tools.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/users.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/agentkit_logs → scalekit_sdk_python-2.18.0/scalekit/utils}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/utils/directory.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/auditlogs → scalekit_sdk_python-2.18.0/scalekit/v1}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/auth → scalekit_sdk_python-2.18.0/scalekit/v1/agentkit_logs}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/agentkit_logs/agentkit_analytics_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/agentkit_logs/agentkit_analytics_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/agentkit_logs/agentkit_analytics_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/agentkit_logs/agentkit_logs_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/agentkit_logs/agentkit_logs_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/agentkit_logs/agentkit_logs_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/clients → scalekit_sdk_python-2.18.0/scalekit/v1/auditlogs}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auditlogs/auditlogs_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auditlogs/auditlogs_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auditlogs/auditlogs_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/commons → scalekit_sdk_python-2.18.0/scalekit/v1/auth}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/auth_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/auth_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/auth_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/passwordless_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/passwordless_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/passwordless_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/totp_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/totp_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/totp_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/webauthn_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/webauthn_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/auth/webauthn_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/connected_accounts → scalekit_sdk_python-2.18.0/scalekit/v1/clients}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/clients/clients_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/clients/clients_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/clients/clients_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/connections → scalekit_sdk_python-2.18.0/scalekit/v1/commons}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/commons/commons_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/commons/commons_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/commons/commons_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/directories → scalekit_sdk_python-2.18.0/scalekit/v1/connected_accounts}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/connected_accounts/connected_accounts_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/connected_accounts/connected_accounts_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/connected_accounts/connected_accounts_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/domains → scalekit_sdk_python-2.18.0/scalekit/v1/connections}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/connections/connections_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/connections/connections_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/connections/connections_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/emails → scalekit_sdk_python-2.18.0/scalekit/v1/directories}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/directories/directories_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/directories/directories_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/directories/directories_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/environments → scalekit_sdk_python-2.18.0/scalekit/v1/domains}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/domains/domains_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/domains/domains_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/domains/domains_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/errdetails → scalekit_sdk_python-2.18.0/scalekit/v1/emails}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/emails/emails_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/emails/emails_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/emails/emails_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/events → scalekit_sdk_python-2.18.0/scalekit/v1/environments}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/environments/environments_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/environments/environments_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/environments/environments_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/gateway → scalekit_sdk_python-2.18.0/scalekit/v1/errdetails}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/errdetails/errdetails_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/errdetails/errdetails_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/errdetails/errdetails_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/interceptors → scalekit_sdk_python-2.18.0/scalekit/v1/events}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/events/events_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/events/events_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/events/events_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/keys → scalekit_sdk_python-2.18.0/scalekit/v1/gateway}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/gateway/gateway_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/gateway/gateway_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/gateway/gateway_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/mcp → scalekit_sdk_python-2.18.0/scalekit/v1/interceptors}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/interceptors/interceptors_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/interceptors/interceptors_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/interceptors/interceptors_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/members → scalekit_sdk_python-2.18.0/scalekit/v1/keys}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/keys/keys_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/keys/keys_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/keys/keys_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/migrations → scalekit_sdk_python-2.18.0/scalekit/v1/mcp}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/mcp/mcp_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/mcp/mcp_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/mcp/mcp_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/options → scalekit_sdk_python-2.18.0/scalekit/v1/members}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/members/members_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/members/members_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/members/members_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/organizations → scalekit_sdk_python-2.18.0/scalekit/v1/migrations}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/migrations/migrations_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/migrations/migrations_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/migrations/migrations_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/providers → scalekit_sdk_python-2.18.0/scalekit/v1/options}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/options/options_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/options/options_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/options/options_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/roles → scalekit_sdk_python-2.18.0/scalekit/v1/organizations}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/organizations/organizations_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/organizations/organizations_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/organizations/organizations_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/secrets → scalekit_sdk_python-2.18.0/scalekit/v1/providers}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/providers/providers_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/providers/providers_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/providers/providers_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/sessions → scalekit_sdk_python-2.18.0/scalekit/v1/roles}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/roles/roles_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/roles/roles_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/roles/roles_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/tokens → scalekit_sdk_python-2.18.0/scalekit/v1/secrets}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/secrets/secrets_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/secrets/secrets_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/secrets/secrets_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/tools → scalekit_sdk_python-2.18.0/scalekit/v1/sessions}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/sessions/sessions_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/sessions/sessions_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/sessions/sessions_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/user_attributes → scalekit_sdk_python-2.18.0/scalekit/v1/tokens}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/tokens/tokens_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/tokens/tokens_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/tokens/tokens_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/users → scalekit_sdk_python-2.18.0/scalekit/v1/tools}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/tools/tools_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/tools/tools_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/tools/tools_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/webhooks → scalekit_sdk_python-2.18.0/scalekit/v1/user_attributes}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/user_attributes/user_attributes_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/user_attributes/user_attributes_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/user_attributes/user_attributes_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0/scalekit/v1/workspaces → scalekit_sdk_python-2.18.0/scalekit/v1/users}/__init__.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/users/users_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/users/users_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/users/users_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/webhooks/webhooks_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/webhooks/webhooks_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/webhooks/webhooks_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/workspaces/workspaces_pb2.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/workspaces/workspaces_pb2.pyi +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/v1/workspaces/workspaces_pb2_grpc.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit/webauthn.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit_sdk_python.egg-info/dependency_links.txt +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/scalekit_sdk_python.egg-info/top_level.txt +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/setup.cfg +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_actions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_connected_accounts.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_connection.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_directory.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_domain.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_events.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_login.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_m2m_client.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_mcp.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_org_roles.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_organization.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_organization_session_policy.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_organization_slug_logo.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_passwordless.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_permissions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_providers.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_role_defaults_dependent.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_roles.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_sessions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_sk819_retry_behavior.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_tokens.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_tools.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_user_roles_permissions.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_users.py +0 -0
- {scalekit_sdk_python-2.16.0 → scalekit_sdk_python-2.18.0}/tests/test_webauthn_credentials.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scalekit-sdk-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.18.0
|
|
4
4
|
Summary: Scalekit official Python SDK
|
|
5
5
|
Home-page: https://github.com/scalekit-inc/scalekit-sdk-python
|
|
6
6
|
Author: Team Scalekit
|
|
@@ -17,7 +17,7 @@ Requires-Dist: google>=3.0
|
|
|
17
17
|
Requires-Dist: requests>=2.34.0
|
|
18
18
|
Requires-Dist: PyJWT>=2.13.0
|
|
19
19
|
Requires-Dist: cffi>=1.15.1
|
|
20
|
-
Requires-Dist: cryptography
|
|
20
|
+
Requires-Dist: cryptography>=50.0.0
|
|
21
21
|
Requires-Dist: setuptools<83.0,>=82.0.1
|
|
22
22
|
Requires-Dist: grpcio-status<2.0,>=1.81.0
|
|
23
23
|
Requires-Dist: protoc-gen-openapiv2>=0.0.1
|
|
@@ -27,6 +27,12 @@ Requires-Dist: python-dotenv<2.0,>=1.2.2
|
|
|
27
27
|
Requires-Dist: Faker<41.0,>=33.0.0
|
|
28
28
|
Requires-Dist: pydantic>=2.13.4
|
|
29
29
|
Requires-Dist: mcp>=1.27.2
|
|
30
|
+
Provides-Extra: flask
|
|
31
|
+
Requires-Dist: flask>=2.0; extra == "flask"
|
|
32
|
+
Provides-Extra: fastapi
|
|
33
|
+
Requires-Dist: fastapi>=0.100; extra == "fastapi"
|
|
34
|
+
Provides-Extra: django
|
|
35
|
+
Requires-Dist: django>=4.2; extra == "django"
|
|
30
36
|
Dynamic: author
|
|
31
37
|
Dynamic: author-email
|
|
32
38
|
Dynamic: classifier
|
|
@@ -35,6 +41,7 @@ Dynamic: description-content-type
|
|
|
35
41
|
Dynamic: home-page
|
|
36
42
|
Dynamic: license
|
|
37
43
|
Dynamic: license-file
|
|
44
|
+
Dynamic: provides-extra
|
|
38
45
|
Dynamic: requires-dist
|
|
39
46
|
Dynamic: summary
|
|
40
47
|
|
|
@@ -178,6 +185,88 @@ Explore fully functional sample applications built with popular Python framework
|
|
|
178
185
|
|-----------|------------|-------------|
|
|
179
186
|
| **FastAPI** | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Modern async Python API framework |
|
|
180
187
|
|
|
188
|
+
### Full Stack Auth — encrypted-session middleware for Flask, FastAPI, and Django
|
|
189
|
+
|
|
190
|
+
The example above is for **Modular SSO**: Scalekit brokers the OAuth exchange with your customer's own IdP via a `connection_id`, and your app owns its own session however it likes.
|
|
191
|
+
|
|
192
|
+
If instead Scalekit hosts your login UI and you want it to also manage the session lifecycle for you (**Full Stack Auth**), `scalekit-sdk-python` ships optional Flask, FastAPI, and Django extras that handle the encrypted session cookie, transparent token refresh, CSRF-safe login/callback, and full logout for you — no hand-rolled cookies, no manual refresh timing.
|
|
193
|
+
|
|
194
|
+
Register these under **Dashboard → Authentication → Redirects** before testing:
|
|
195
|
+
- **Redirect URI** — your `redirect_uri` (the `/callback` path). Scalekit rejects the exchange if this doesn't match exactly.
|
|
196
|
+
- **Post Logout Redirect URI** — where users land after full logout. A relative path gets auto-absolutized against the request host, but the resulting absolute URL must still be registered.
|
|
197
|
+
- **Initiate Login URL** — your `/login` path. Scalekit redirects here (not `/callback`) for a bookmarked login page, an IdP portal tile, or an invite/magic link — the login view already handles this correctly, including the `idp_initiated_login` case, with no extra code required.
|
|
198
|
+
|
|
199
|
+
pip install "scalekit-sdk-python[flask]" # or "scalekit-sdk-python[fastapi]" or "scalekit-sdk-python[django]"
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
# Flask
|
|
203
|
+
import os
|
|
204
|
+
from flask import Flask
|
|
205
|
+
from scalekit.frameworks.flask import ScalekitAuth
|
|
206
|
+
|
|
207
|
+
app = Flask(__name__)
|
|
208
|
+
auth = ScalekitAuth(
|
|
209
|
+
app,
|
|
210
|
+
env_url=os.environ["SCALEKIT_ENV_URL"],
|
|
211
|
+
client_id=os.environ["SCALEKIT_CLIENT_ID"],
|
|
212
|
+
client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
|
|
213
|
+
redirect_uri="https://myapp.com/callback",
|
|
214
|
+
cookie_encryption_secret=os.environ["COOKIE_ENCRYPTION_SECRET"], # openssl rand -base64 32
|
|
215
|
+
) # registers /login, /callback, /logout
|
|
216
|
+
|
|
217
|
+
@app.route("/account")
|
|
218
|
+
@auth.requires_auth
|
|
219
|
+
def account():
|
|
220
|
+
return {"email": auth.current_user["email"]}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
# FastAPI -- protect routes with Depends(), FastAPI's idiomatic mechanism
|
|
225
|
+
import os
|
|
226
|
+
from fastapi import Depends, FastAPI
|
|
227
|
+
from scalekit.frameworks.fastapi import ScalekitAuth
|
|
228
|
+
|
|
229
|
+
app = FastAPI()
|
|
230
|
+
auth = ScalekitAuth(
|
|
231
|
+
env_url=os.environ["SCALEKIT_ENV_URL"],
|
|
232
|
+
client_id=os.environ["SCALEKIT_CLIENT_ID"],
|
|
233
|
+
client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
|
|
234
|
+
redirect_uri="https://myapp.com/callback",
|
|
235
|
+
cookie_encryption_secret=os.environ["COOKIE_ENCRYPTION_SECRET"],
|
|
236
|
+
)
|
|
237
|
+
auth.install(app) # registers /login, /callback, /logout
|
|
238
|
+
|
|
239
|
+
@app.get("/account")
|
|
240
|
+
async def account(user: dict = Depends(auth.requires_auth)):
|
|
241
|
+
return {"email": user["email"]}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
# Django -- settings.py
|
|
246
|
+
import os
|
|
247
|
+
|
|
248
|
+
MIDDLEWARE = [..., "scalekit.frameworks.django.ScalekitAuthMiddleware"]
|
|
249
|
+
SCALEKIT_ENV_URL = os.environ["SCALEKIT_ENV_URL"]
|
|
250
|
+
SCALEKIT_CLIENT_ID = os.environ["SCALEKIT_CLIENT_ID"]
|
|
251
|
+
SCALEKIT_CLIENT_SECRET = os.environ["SCALEKIT_CLIENT_SECRET"]
|
|
252
|
+
SCALEKIT_REDIRECT_URI = "https://myapp.com/callback"
|
|
253
|
+
SCALEKIT_COOKIE_ENCRYPTION_SECRET = os.environ["COOKIE_ENCRYPTION_SECRET"]
|
|
254
|
+
|
|
255
|
+
# urls.py
|
|
256
|
+
from django.urls import include, path
|
|
257
|
+
urlpatterns = [path("", include("scalekit.frameworks.django")), ...] # /login, /callback, /logout
|
|
258
|
+
|
|
259
|
+
# views.py
|
|
260
|
+
from django.http import JsonResponse
|
|
261
|
+
from scalekit.frameworks.django import login_required
|
|
262
|
+
|
|
263
|
+
@login_required
|
|
264
|
+
def account(request):
|
|
265
|
+
return JsonResponse(request.scalekit_user)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
See [`examples/flask`](./examples/flask), [`examples/fastapi`](./examples/fastapi), and [`examples/django`](./examples/django) for complete, runnable versions. For a fuller production-oriented sample app, see the framework repos above.
|
|
269
|
+
|
|
181
270
|
## 🔗 Helpful Links
|
|
182
271
|
|
|
183
272
|
### 📖 Quickstart Guides
|
|
@@ -138,6 +138,88 @@ Explore fully functional sample applications built with popular Python framework
|
|
|
138
138
|
|-----------|------------|-------------|
|
|
139
139
|
| **FastAPI** | [scalekit-fastapi-example](https://github.com/scalekit-developers/scalekit-fastapi-example) | Modern async Python API framework |
|
|
140
140
|
|
|
141
|
+
### Full Stack Auth — encrypted-session middleware for Flask, FastAPI, and Django
|
|
142
|
+
|
|
143
|
+
The example above is for **Modular SSO**: Scalekit brokers the OAuth exchange with your customer's own IdP via a `connection_id`, and your app owns its own session however it likes.
|
|
144
|
+
|
|
145
|
+
If instead Scalekit hosts your login UI and you want it to also manage the session lifecycle for you (**Full Stack Auth**), `scalekit-sdk-python` ships optional Flask, FastAPI, and Django extras that handle the encrypted session cookie, transparent token refresh, CSRF-safe login/callback, and full logout for you — no hand-rolled cookies, no manual refresh timing.
|
|
146
|
+
|
|
147
|
+
Register these under **Dashboard → Authentication → Redirects** before testing:
|
|
148
|
+
- **Redirect URI** — your `redirect_uri` (the `/callback` path). Scalekit rejects the exchange if this doesn't match exactly.
|
|
149
|
+
- **Post Logout Redirect URI** — where users land after full logout. A relative path gets auto-absolutized against the request host, but the resulting absolute URL must still be registered.
|
|
150
|
+
- **Initiate Login URL** — your `/login` path. Scalekit redirects here (not `/callback`) for a bookmarked login page, an IdP portal tile, or an invite/magic link — the login view already handles this correctly, including the `idp_initiated_login` case, with no extra code required.
|
|
151
|
+
|
|
152
|
+
pip install "scalekit-sdk-python[flask]" # or "scalekit-sdk-python[fastapi]" or "scalekit-sdk-python[django]"
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
# Flask
|
|
156
|
+
import os
|
|
157
|
+
from flask import Flask
|
|
158
|
+
from scalekit.frameworks.flask import ScalekitAuth
|
|
159
|
+
|
|
160
|
+
app = Flask(__name__)
|
|
161
|
+
auth = ScalekitAuth(
|
|
162
|
+
app,
|
|
163
|
+
env_url=os.environ["SCALEKIT_ENV_URL"],
|
|
164
|
+
client_id=os.environ["SCALEKIT_CLIENT_ID"],
|
|
165
|
+
client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
|
|
166
|
+
redirect_uri="https://myapp.com/callback",
|
|
167
|
+
cookie_encryption_secret=os.environ["COOKIE_ENCRYPTION_SECRET"], # openssl rand -base64 32
|
|
168
|
+
) # registers /login, /callback, /logout
|
|
169
|
+
|
|
170
|
+
@app.route("/account")
|
|
171
|
+
@auth.requires_auth
|
|
172
|
+
def account():
|
|
173
|
+
return {"email": auth.current_user["email"]}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
# FastAPI -- protect routes with Depends(), FastAPI's idiomatic mechanism
|
|
178
|
+
import os
|
|
179
|
+
from fastapi import Depends, FastAPI
|
|
180
|
+
from scalekit.frameworks.fastapi import ScalekitAuth
|
|
181
|
+
|
|
182
|
+
app = FastAPI()
|
|
183
|
+
auth = ScalekitAuth(
|
|
184
|
+
env_url=os.environ["SCALEKIT_ENV_URL"],
|
|
185
|
+
client_id=os.environ["SCALEKIT_CLIENT_ID"],
|
|
186
|
+
client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
|
|
187
|
+
redirect_uri="https://myapp.com/callback",
|
|
188
|
+
cookie_encryption_secret=os.environ["COOKIE_ENCRYPTION_SECRET"],
|
|
189
|
+
)
|
|
190
|
+
auth.install(app) # registers /login, /callback, /logout
|
|
191
|
+
|
|
192
|
+
@app.get("/account")
|
|
193
|
+
async def account(user: dict = Depends(auth.requires_auth)):
|
|
194
|
+
return {"email": user["email"]}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
# Django -- settings.py
|
|
199
|
+
import os
|
|
200
|
+
|
|
201
|
+
MIDDLEWARE = [..., "scalekit.frameworks.django.ScalekitAuthMiddleware"]
|
|
202
|
+
SCALEKIT_ENV_URL = os.environ["SCALEKIT_ENV_URL"]
|
|
203
|
+
SCALEKIT_CLIENT_ID = os.environ["SCALEKIT_CLIENT_ID"]
|
|
204
|
+
SCALEKIT_CLIENT_SECRET = os.environ["SCALEKIT_CLIENT_SECRET"]
|
|
205
|
+
SCALEKIT_REDIRECT_URI = "https://myapp.com/callback"
|
|
206
|
+
SCALEKIT_COOKIE_ENCRYPTION_SECRET = os.environ["COOKIE_ENCRYPTION_SECRET"]
|
|
207
|
+
|
|
208
|
+
# urls.py
|
|
209
|
+
from django.urls import include, path
|
|
210
|
+
urlpatterns = [path("", include("scalekit.frameworks.django")), ...] # /login, /callback, /logout
|
|
211
|
+
|
|
212
|
+
# views.py
|
|
213
|
+
from django.http import JsonResponse
|
|
214
|
+
from scalekit.frameworks.django import login_required
|
|
215
|
+
|
|
216
|
+
@login_required
|
|
217
|
+
def account(request):
|
|
218
|
+
return JsonResponse(request.scalekit_user)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
See [`examples/flask`](./examples/flask), [`examples/fastapi`](./examples/fastapi), and [`examples/django`](./examples/django) for complete, runnable versions. For a fuller production-oriented sample app, see the framework repos above.
|
|
222
|
+
|
|
141
223
|
## 🔗 Helpful Links
|
|
142
224
|
|
|
143
225
|
### 📖 Quickstart Guides
|
|
@@ -9,7 +9,7 @@ import hmac
|
|
|
9
9
|
import hashlib
|
|
10
10
|
import base64
|
|
11
11
|
from datetime import datetime, timedelta, timezone
|
|
12
|
-
from scalekit.core import CoreClient
|
|
12
|
+
from scalekit.core import CoreClient, DEFAULT_KEEPALIVE_TIME_MS, DEFAULT_KEEPALIVE_TIMEOUT_MS
|
|
13
13
|
from scalekit.domain import DomainClient
|
|
14
14
|
from scalekit.connection import ConnectionClient
|
|
15
15
|
from scalekit.m2m_client import M2MClient
|
|
@@ -50,23 +50,46 @@ webhook_signature_version = "v1"
|
|
|
50
50
|
class ScalekitClient:
|
|
51
51
|
""" Class definition for scalekit client """
|
|
52
52
|
|
|
53
|
-
def __init__(
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
env_url: str,
|
|
56
|
+
client_id: str,
|
|
57
|
+
client_secret: str,
|
|
58
|
+
keepalive_time_ms: int = DEFAULT_KEEPALIVE_TIME_MS,
|
|
59
|
+
keepalive_timeout_ms: int = DEFAULT_KEEPALIVE_TIMEOUT_MS,
|
|
60
|
+
):
|
|
54
61
|
"""
|
|
55
62
|
Initializer for Scalekit base class
|
|
56
63
|
|
|
57
|
-
:param env_url
|
|
58
|
-
:type
|
|
59
|
-
:param client_id
|
|
60
|
-
:type
|
|
61
|
-
:param client_secret
|
|
62
|
-
:type
|
|
64
|
+
:param env_url : Environment URL
|
|
65
|
+
:type : ``` str ```
|
|
66
|
+
:param client_id : Client ID
|
|
67
|
+
:type : ``` str ```
|
|
68
|
+
:param client_secret : Client Secret
|
|
69
|
+
:type : ``` str ```
|
|
70
|
+
:param keepalive_time_ms : How often, in milliseconds, an idle gRPC
|
|
71
|
+
connection is verified before reuse.
|
|
72
|
+
Defaults to 60000; most callers never
|
|
73
|
+
need to set this. Set to 0 to disable
|
|
74
|
+
keepalive entirely.
|
|
75
|
+
:type : ``` int ```
|
|
76
|
+
:param keepalive_timeout_ms : How long, in milliseconds, to wait for a
|
|
77
|
+
keepalive response before treating an
|
|
78
|
+
idle connection as dead. Defaults to
|
|
79
|
+
10000.
|
|
80
|
+
:type : ``` int ```
|
|
63
81
|
|
|
64
82
|
:returns:
|
|
65
83
|
None
|
|
66
84
|
"""
|
|
67
85
|
try:
|
|
68
86
|
self.core_client = CoreClient(
|
|
69
|
-
env_url=env_url,
|
|
87
|
+
env_url=env_url,
|
|
88
|
+
client_id=client_id,
|
|
89
|
+
client_secret=client_secret,
|
|
90
|
+
keepalive_time_ms=keepalive_time_ms,
|
|
91
|
+
keepalive_timeout_ms=keepalive_timeout_ms,
|
|
92
|
+
)
|
|
70
93
|
self.domain = DomainClient(self.core_client)
|
|
71
94
|
self.connection = ConnectionClient(self.core_client)
|
|
72
95
|
self.organization = OrganizationClient(self.core_client)
|
|
@@ -19,6 +19,33 @@ TMetadata = TypeVar("TMetadata")
|
|
|
19
19
|
TOKEN_ENDPOINT = "/oauth/token"
|
|
20
20
|
JWKS_ENDPOINT = "/keys"
|
|
21
21
|
|
|
22
|
+
# Must clear the backend's EnforcementPolicy.MinTime (30s, scalekit's
|
|
23
|
+
# cmd/grpc.go) with real margin, not just match it: grpc-core pings on this
|
|
24
|
+
# exact interval for as long as the channel is open (keepalive_permit_without_calls
|
|
25
|
+
# below), so a value equal to MinTime leaves zero room for jitter between the
|
|
26
|
+
# client's timer and the server's strike window — one early ping is a strike,
|
|
27
|
+
# three and the server GOAWAYs the connection, recreating the bug this fixes.
|
|
28
|
+
# 60s matches the Java SDK's default for the same reason.
|
|
29
|
+
DEFAULT_KEEPALIVE_TIME_MS = 60_000
|
|
30
|
+
DEFAULT_KEEPALIVE_TIMEOUT_MS = 10_000
|
|
31
|
+
|
|
32
|
+
# The floor tracks DEFAULT_KEEPALIVE_TIME_MS for the reason spelled out above:
|
|
33
|
+
# the backend's EnforcementPolicy.MinTime is 30s, and a value at exactly 30s has
|
|
34
|
+
# zero jitter headroom — grpc's ping timer drifts slightly early, so an early
|
|
35
|
+
# ping counts as a strike and enough strikes make the server GOAWAY. 60s gives
|
|
36
|
+
# 2x margin over the 30s MinTime. Since there is no legitimate reason to go below
|
|
37
|
+
# the default, the only sensible choices are 0 (disabled) or >= 60s. (gRPC also
|
|
38
|
+
# silently clamps sub-10s values up to 10s per grpc/proposal A8, so a small value
|
|
39
|
+
# never even reaches the wire as requested.) Reject 1..59999.
|
|
40
|
+
MIN_KEEPALIVE_TIME_MS = 60_000
|
|
41
|
+
|
|
42
|
+
# requests defaults to no timeout, so a black-holed connection blocks the
|
|
43
|
+
# calling thread until the OS abandons the socket. Bound the connect and read
|
|
44
|
+
# phases separately with a (connect, read) tuple.
|
|
45
|
+
DEFAULT_HTTP_CONNECT_TIMEOUT_S = 10
|
|
46
|
+
DEFAULT_HTTP_READ_TIMEOUT_S = 30
|
|
47
|
+
DEFAULT_HTTP_TIMEOUT = (DEFAULT_HTTP_CONNECT_TIMEOUT_S, DEFAULT_HTTP_READ_TIMEOUT_S)
|
|
48
|
+
|
|
22
49
|
|
|
23
50
|
class WithCall(Protocol):
|
|
24
51
|
def __call__(self, request: TRequest, metadata: TMetadata) -> TResponse: ...
|
|
@@ -32,16 +59,36 @@ class CoreClient:
|
|
|
32
59
|
api_version = "20260727"
|
|
33
60
|
user_agent = f"{sdk_version} Python/{platform.python_version()} ({platform.system()}; {platform.architecture()}"
|
|
34
61
|
|
|
35
|
-
def __init__(
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
env_url,
|
|
65
|
+
client_id,
|
|
66
|
+
client_secret,
|
|
67
|
+
keepalive_time_ms: int = DEFAULT_KEEPALIVE_TIME_MS,
|
|
68
|
+
keepalive_timeout_ms: int = DEFAULT_KEEPALIVE_TIMEOUT_MS,
|
|
69
|
+
):
|
|
36
70
|
"""
|
|
37
71
|
Initializer for Core client
|
|
38
72
|
|
|
39
|
-
:param env_url
|
|
40
|
-
:type
|
|
41
|
-
:param client_id
|
|
42
|
-
:type
|
|
43
|
-
:param client_secret
|
|
44
|
-
:type
|
|
73
|
+
:param env_url : Environment URL
|
|
74
|
+
:type : ``` str ```
|
|
75
|
+
:param client_id : Client ID
|
|
76
|
+
:type : ``` str ```
|
|
77
|
+
:param client_secret : Client Secret
|
|
78
|
+
:type : ``` str ```
|
|
79
|
+
:param keepalive_time_ms : How often, in milliseconds, an idle gRPC
|
|
80
|
+
connection is verified before reuse.
|
|
81
|
+
Must stay above the backend's keepalive
|
|
82
|
+
MinTime (30s) with real margin, or the
|
|
83
|
+
server treats this ping as abuse. Defaults
|
|
84
|
+
to 60000. Set to 0 to disable keepalive
|
|
85
|
+
entirely.
|
|
86
|
+
:type : ``` int ```
|
|
87
|
+
:param keepalive_timeout_ms : How long, in milliseconds, to wait for a
|
|
88
|
+
keepalive response before treating an
|
|
89
|
+
idle connection as dead. Defaults to
|
|
90
|
+
10000.
|
|
91
|
+
:type : ``` int ```
|
|
45
92
|
:returns
|
|
46
93
|
None
|
|
47
94
|
"""
|
|
@@ -50,6 +97,20 @@ class CoreClient:
|
|
|
50
97
|
self.env_url = env_url
|
|
51
98
|
self.client_id = client_id
|
|
52
99
|
self.client_secret = client_secret
|
|
100
|
+
# 0 means "disabled" and is allowed through deliberately; only 1..59999
|
|
101
|
+
# is rejected. A value below the 60s default leaves too little margin
|
|
102
|
+
# over the Scalekit server's 30s MinTime — an early ping gets struck as
|
|
103
|
+
# abusive and the server GOAWAYs — and gRPC silently raises sub-10s
|
|
104
|
+
# values to 10s, so a small value is never what the caller asked for.
|
|
105
|
+
if keepalive_time_ms and keepalive_time_ms < MIN_KEEPALIVE_TIME_MS:
|
|
106
|
+
raise ValueError(
|
|
107
|
+
f"keepalive_time_ms must be 0 (disabled) or >= {MIN_KEEPALIVE_TIME_MS}; "
|
|
108
|
+
f"got {keepalive_time_ms}. A value below the default leaves too little "
|
|
109
|
+
"margin over the Scalekit server's 30s MinTime (early pings are struck "
|
|
110
|
+
"as abusive), and gRPC silently raises sub-10s values to 10s."
|
|
111
|
+
)
|
|
112
|
+
self.keepalive_time_ms = keepalive_time_ms
|
|
113
|
+
self.keepalive_timeout_ms = keepalive_timeout_ms
|
|
53
114
|
self.keys = {}
|
|
54
115
|
self.access_token = None
|
|
55
116
|
self.grpc_secure_channel = None
|
|
@@ -70,7 +131,24 @@ class CoreClient:
|
|
|
70
131
|
channel_credentials,
|
|
71
132
|
call_credentials,
|
|
72
133
|
)
|
|
73
|
-
|
|
134
|
+
# keepalive_time_ms == 0 disables keepalive entirely: no options are
|
|
135
|
+
# passed, so grpc-core falls back to its own defaults (no idle pings).
|
|
136
|
+
channel_options = []
|
|
137
|
+
if self.keepalive_time_ms:
|
|
138
|
+
# keepalive_permit_without_calls=1 so an idle channel is still
|
|
139
|
+
# periodically verified: without it, grpc-core only sends HTTP/2
|
|
140
|
+
# keepalive PINGs while there are active calls, so a connection
|
|
141
|
+
# silently dropped by a network intermediary while idle isn't
|
|
142
|
+
# detected until the next real call is written to it.
|
|
143
|
+
channel_options = [
|
|
144
|
+
('grpc.keepalive_time_ms', self.keepalive_time_ms),
|
|
145
|
+
('grpc.keepalive_timeout_ms', self.keepalive_timeout_ms),
|
|
146
|
+
('grpc.keepalive_permit_without_calls', 1),
|
|
147
|
+
('grpc.http2.max_pings_without_data', 0),
|
|
148
|
+
]
|
|
149
|
+
self.grpc_secure_channel = grpc.secure_channel(
|
|
150
|
+
self.host, composite_credentials, options=channel_options
|
|
151
|
+
)
|
|
74
152
|
|
|
75
153
|
def __authenticate_client(self):
|
|
76
154
|
"""
|
|
@@ -104,6 +182,7 @@ class CoreClient:
|
|
|
104
182
|
headers=self.get_headers(headers=headers),
|
|
105
183
|
data=data,
|
|
106
184
|
verify=True,
|
|
185
|
+
timeout=DEFAULT_HTTP_TIMEOUT,
|
|
107
186
|
)
|
|
108
187
|
if response.status_code != 200:
|
|
109
188
|
raise ScalekitServerException.promote(response)
|
|
@@ -114,7 +193,9 @@ class CoreClient:
|
|
|
114
193
|
if self.keys and len(self.keys) > 0:
|
|
115
194
|
return
|
|
116
195
|
response = requests.get(
|
|
117
|
-
self.env_url + JWKS_ENDPOINT,
|
|
196
|
+
self.env_url + JWKS_ENDPOINT,
|
|
197
|
+
headers=self.get_headers(),
|
|
198
|
+
timeout=DEFAULT_HTTP_TIMEOUT,
|
|
118
199
|
)
|
|
119
200
|
response = json.loads(response.content)
|
|
120
201
|
keys = response["keys"]
|