Python SDK for Burdenoff Workspace Server
Project description
// ... existing code ...
login(email, password)
Authenticates a user with their email and password.
Parameters:
email(str): The user's email addresspassword(str): The user's password
Returns:
- JWT token string if successful, None if failed
Example:
# Request
token = await client.auth.login("user@example.com", "your-secure-password")
# Example Response (Success)
# "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
# Example Response (Failure)
# None
refresh_token(token)
Refreshes an existing authentication token.
Parameters:
token(str): Current authentication token
Returns:
- New JWT token string if successful, None if failed
Example:
# Request
# Assuming client.token holds a valid, refreshable token
new_token = await client.auth.refresh_token(client.token)
# Example Response (Success)
# "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyNDI2MjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
# Example Response (Failure)
# None
logout(token)
Invalidates an authentication token.
Parameters:
token(str): Authentication token to invalidate
Returns:
- Boolean indicating success
Example:
# Request
# Assuming client.token holds a valid token
success = await client.auth.logout(client.token)
# Example Response (Success)
# True
# Example Response (Failure - e.g., token already invalid)
# False
verify_jwt(token)
Verifies if a token is valid by asynchronously calling an external verification endpoint.
Parameters:
token(str): Authentication token to verify
Returns:
bool: Indicating if token is valid
Note: This method is now asynchronous and must be called with await. It uses an underlying asynchronous HTTP client (e.g., aiohttp).
Example:
import asyncio
# Presuming client is an initialized WorkspaceClient with an async-capable Auth class
# async def main():
# is_valid = await client.auth.verify_jwt("some_jwt_token_string")
# print(f"Token is valid: {is_valid}")
#
# asyncio.run(main())
# Example Response (Valid Token)
# True
# Example Response (Invalid Token)
# False
get_context(token, metadata=None) (Now an internal method _get_context used by guardRequest)
Asynchronously decodes a JWT and returns its payload...
This function has been refactored into an internal method _get_context within the Auth class. It's used by guardRequest to decode the JWT and enrich it with additional user, organization, tenant, and product information. The enriched context is then made available through the context field in the guardRequest response.
guardRequest(jwt_token, operation, metadata=None)
This is a central asynchronous method designed to be invoked for every operation that requires protection. It performs initial authentication (via verify_jwt) and then retrieves an enriched context (via an internal _get_context call). It includes placeholders for future authorization (RBAC) and billing checks.
Note: This method is asynchronous and must be called with await.
Parameters:
jwt_token(str): The JWT string to validate.operation(str): A string identifying the operation being attempted. This will be used for future RBAC checks (e.g., "create_document", "read_user_profile").metadata(Optional[Dict[str, Any]]): An optional dictionary for passing additional data. This can influence what details are fetched for the context (e.g.,{"fetch_product_info": True}) or be used by future RBAC/billing logic.
Returns:
Dict[str, Any]: A dictionary containing the results of the checks:isAuthenticated(bool):Trueif thejwt_tokenis successfully verified,Falseotherwise.context(Optional[Dict[str, Any]]): IfisAuthenticatedisTrueand context retrieval is successful, this field contains an enriched dictionary.- Note on Current Implementation (Fake User DB for Migration): For development and migration purposes, the
_get_contextmethod (called internally byguardRequest) currently returns a predefined context for a 'test_user', largely irrespective of the input token's actual content (though the token must be a syntactically valid JWT). This ensures API endpoints can be refactored to use the new context structure without immediately requiring live backend services for user/org/tenant data. This fake data includes illustrative user, organization, tenant, and product details. - In a future production state, this context will be dynamically built based on the validated JWT and real-time calls to backend services for enrichment.
- The structure includes:
- Core claims from the JWT (excluding standard JWT-specific claims like
exp,iat). - User Details: (e.g.,
context['user'] = {'id': 'test_user_001', 'name': 'Test User Default', 'email': 'testuser@example.com', 'roles': ['test_role_admin'], 'is_active': True}). - Organization Details: (e.g.,
context['organization'] = {'id': 'test_org_001', 'name': 'Test Organization for test_user_001', 'plan': 'premium_test_plan'}). - Tenant Details: (e.g.,
context['tenant'] = {'id': 'test_tenant_001', 'name': 'Test Tenant for test_user_001', 'region': 'test_region_1'}). - Product/Service Details: (e.g.,
context['product'] = {'name': 'FluidGrids Workflow Engine (Test Context)', 'version_subscribed': 'dev-latest'}). This field isNoneif authentication fails or if context processing encounters an unrecoverable error.
- Core claims from the JWT (excluding standard JWT-specific claims like
- Note on Current Implementation (Fake User DB for Migration): For development and migration purposes, the
isAuthorized(Optional[bool]): Placeholder for future RBAC checks. Currently alwaysNone.hasSufficientCredits(Optional[bool]): Placeholder for future billing checks. Currently alwaysNone.error(Optional[str]): A string describing any error encountered.
Behavior:
- Asynchronously calls
await self.verify_jwt(jwt_token). - If
verify_jwtfails,isAuthenticatedisFalse. - If
verify_jwtsucceeds, it then asynchronously calls an internalawait self._get_context(jwt_token, metadata)method._get_contextdecodes the JWT and currently provides a predefined 'test_user' context with enriched user, organization, tenant, and product details.- If
_get_contextfails (e.g.,jwt.ExpiredSignatureError,jwt.InvalidTokenError, or issues during data fetching),isAuthenticatedmay be set toFalse, and anerrormessage is populated. Thecontextwill likely beNone.
Example Usage (within the SDK, assuming client.auth is an instance of Auth):
import asyncio
# async def main():
# # Presuming client is an initialized WorkspaceClient
# # burdenoff_auth_service = client.auth
# # jwt_token = "your_jwt_token_string"
# # operation_name = "access_sensitive_data"
#
# guard_response = await burdenoff_auth_service.guardRequest(jwt_token, operation_name)
#
# if guard_response["isAuthenticated"] and guard_response["context"] is not None:
# print(f"User authenticated.")
# user_info = guard_response["context"].get("user")
# org_info = guard_response["context"].get("organization")
# if user_info:
# print(f" User ID: {user_info.get('id')}, Name: {user_info.get('name')}")
# if org_info:
# print(f" Organization ID: {org_info.get('id')}, Plan: {org_info.get('plan')}")
#
# # Hypothetical check for future RBAC/Billing
# # if guard_response["isAuthorized"] is not False and guard_response["hasSufficientCredits"] is not False:
# # print("Operation can proceed.")
# # else:
# # print(f"Operation cannot proceed. Authz: {guard_response['isAuthorized']}, Credits: {guard_response['hasSufficientCredits']}")
# else:
# print(f"Authentication or context processing failed: {guard_response['error']}")
#
# # asyncio.run(main())
FastAPI Integration (FluidGrids Workflow Engine Example)
The burdenoff-common SDK, particularly its Auth class with guardRequest, can be integrated into a FastAPI application to protect endpoints. The context provided by guardRequest will be enriched as described above.
1. Initialization
(Example for app.py lifespan remains largely the same - it initializes BurdenoffAuth which now has the enhanced _get_context internally.)
# In your FastAPI app.py or similar
# ... (imports and lifespan setup as previously documented) ...
# app.state.burdenoff_auth_service = BurdenoffAuth(client=burdenoff_client)
# ...
2. Authentication Middleware
(The middleware example remains the same. It populates request.state.user_context with the context from guardRequest.)
# In your middleware/burdenoff_auth_middleware.py
# ... (middleware code as previously documented) ...
# request.state.user_context = guard_response.get("context")
# ...
The user_context stored in request.state.user_context will now be the richer context object.
3. FastAPI Dependencies
(Dependencies remain structurally the same, but the type/content of user_context they provide access to is richer.)
Example (dependencies.py):
# ... (imports as previously documented) ...
# async def get_current_user_context(request: Request) -> Optional[Dict[str, Any]]:
# # This will now return the enriched context or None
# return getattr(request.state, 'user_context', None)
# async def require_burdenoff_user_context(request: Request) -> Dict[str, Any]:
# # This will now return the enriched context or raise an error
# # ... (logic as previously documented)
# user_context = getattr(request.state, 'user_context', None)
# # ... (validation logic)
# return user_context
4. Using Dependencies in Routes
Your route handlers can now access the more detailed information from the context.
Example Route:
from fastapi import APIRouter, Depends, FastAPI
from typing import Dict, Any, Optional # For type hints
# Assume dependencies are defined as shown previously and imported
# async def require_burdenoff_user_context(request: Request) -> Dict[str, Any]: ...
# async def get_current_user_context(request: Request) -> Optional[Dict[str, Any]]: ...
# app = FastAPI() # Assuming app is defined with lifespan and middleware
# router = APIRouter()
# @router.get("/my-protected-resource")
# async def get_protected_resource(
# # user_ctx is the enriched context
# user_ctx: Dict[str, Any] = Depends(require_burdenoff_user_context)
# ):
# user_details = user_ctx.get("user", {})
# org_details = user_ctx.get("organization", {})
#
# return {
# "message": "Hello, this is a protected resource!",
# "user_id": user_details.get("id"),
# "user_email": user_details.get("email"),
# "organization_name": org_details.get("name"),
# "raw_jwt_custom_claim": user_ctx.get("custom_claim_from_jwt") # If present
# }
# @router.get("/my-optional-auth-resource")
# async def get_optional_resource(
# # user_ctx is the enriched context if user is authenticated
# user_ctx: Optional[Dict[str, Any]] = Depends(get_current_user_context)
# ):
# if user_ctx and user_ctx.get("user"):
# return {
# "message": "Hello, authenticated user!",
# "user_id": user_ctx.get("user").get("id"),
# "tenant_id": user_ctx.get("tenant", {}).get("id")
# }
# return {"message": "Hello, guest! This resource is accessible to all."}
# app.include_router(router, prefix="/api/v1/app") # Example prefix
This enriched context allows for more fine-grained decisions and data availability directly after authentication, streamlining access to common user, organization, and tenant information within your API endpoints.
Example Route (Illustrating access to fake context structure):
...
async def get_protected_resource(
user_ctx: Dict[str, Any] = Depends(require_burdenoff_user_context)
):
user_details = user_ctx.get("user", {})
org_details = user_ctx.get("organization", {})
# Accessing fake data like:
# user_details.get("id") will be "test_user_001" (or from token if provided)
# user_details.get("email") will be "testuser@example.com" (or from token)
# org_details.get("plan") will be "premium_test_plan"
return { ... }
...
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file burdenoff_common-0.3.0.tar.gz.
File metadata
- Download URL: burdenoff_common-0.3.0.tar.gz
- Upload date:
- Size: 30.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db878ff1f82a96e54c15934d648543ee9e9876a74bc0abe7f53718fb275a9ef8
|
|
| MD5 |
795d277efa88142399c009a3b9b535e2
|
|
| BLAKE2b-256 |
3603643dc7e51b110b02686627effb7408a6d1a7941c9c6fb37021c51475aed7
|
File details
Details for the file burdenoff_common-0.3.0-py3-none-any.whl.
File metadata
- Download URL: burdenoff_common-0.3.0-py3-none-any.whl
- Upload date:
- Size: 33.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b66963cc03cfe92d6a9c6631a12723b709c2e28c69119b8b0be779956344d28
|
|
| MD5 |
803225cba060659891295c548fc3d6c4
|
|
| BLAKE2b-256 |
e82a65aa4f360b9d3a625c76739c26acf8b16f8014239ae6c7ef75f6c306d683
|