Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dependencies = [
"pydantic",
"fastapi",
"sentry-sdk[fastapi]",
"httpx (>=0.28.1,<0.29.0)",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image its better use with http2 support

]

[project.optional-dependencies]
Expand Down
7 changes: 7 additions & 0 deletions vp_core/clients/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
HTTP client utilities for interacting with external/internal services.
"""

from .volopay_be import validate_token

__all__ = ["validate_token"]
112 changes: 112 additions & 0 deletions vp_core/clients/volopay_be.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"""
Volopay Backend (volo-be) HTTP client utilities.

This module provides shared utilities for microservices that need to interact
with the main volo-be backend, primarily for auth token validation.

Usage:
from vp_core.clients.volopay_be import validate_token

valid = await validate_token(
client="web",
access_token="abc123",
uid="user@example.com",
account="volopay",
volo_be_url="https://api.volopay.com"
)
"""

import httpx


async def validate_token(
client: str,
access_token: str,
uid: str,
account: str,
volo_be_url: str,
x_feature: str | None = None,
env: str | None = None,
) -> bool:
"""
Validates a user's session token by calling volo-be's token validation endpoint.

This is used by satellite microservices (volo-agents, ocr-reader, etc.) to verify
that a frontend user's token is valid without maintaining their own user database.

Args:
client: Client identifier (e.g., "web", "mobile")
access_token: User's session access token
uid: User identifier (typically email)
account: Account/organization identifier
volo_be_url: Base URL of volo-be (e.g., "https://api.volopay.com")
x_feature: Optional feature flag header
env: Environment name (defaults to None). If "test", always returns True.

Returns:
True if the token is valid (volo-be returned 200), False otherwise.

Example:
>>> valid = await validate_token(
... client="web",
... access_token="eyJ0eXAi...",
... uid="user@example.com",
... account="volopay",
... volo_be_url="https://api.volopay.com"
... )
>>> if valid:
... # proceed with authenticated request
"""
# Skip validation in test environments
if env == "test":
return True
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are using this env bro. seems we can skip this function call itself na


headers = {
"client": client,
"access-token": access_token,
"uid": uid,
"account": account,
}

# Add optional x_feature header if provided
if x_feature:
headers["x_feature"] = x_feature

async with httpx.AsyncClient(base_url=volo_be_url, headers=headers) as http:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel it should change base url as well. based on the request u are getting

try:
response = await http.get("/api/v3/auth/user/validate_token")
return response.status_code == 200
except httpx.HTTPError:
# Network errors, timeouts, etc. — treat as invalid token
return False


# Future: Two-layer auth builder
# When multiple microservices (volo-agents, ocr-reader, future services) all adopt
# the same two-layer auth pattern (shared secret + token validation fallback),
# consider adding a generic FastAPI dependency builder here:
#
# def create_two_layer_auth_dependency(
# service_name: str, # "agents", "ocr", etc.
# secret_env_var: str, # "VOLO_BE_AGENTS_SECRET"
# volo_be_url_env_var: str = "VOLO_BE_URL",
# env_var: str = "ENV"
# ) -> Callable:
# """
# Creates a FastAPI Depends() function that enforces two-layer auth:
# 1. Checks volo_be_{service_name}_secret header against env var
# 2. Falls back to validate_token() if Layer 1 fails
#
# Returns:
# A FastAPI dependency (Depends-compatible callable)
#
# Example:
# from vp_core.clients import create_two_layer_auth_dependency
#
# AuthDep = create_two_layer_auth_dependency(
# service_name="agents",
# secret_env_var="VOLO_BE_AGENTS_SECRET"
# )
#
# app.include_router(router, dependencies=[AuthDep])
# """