vs-security 0.1.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.
@@ -0,0 +1,29 @@
1
+ Metadata-Version: 2.4
2
+ Name: vs-security
3
+ Version: 0.1.0
4
+ Summary: Security library for Viveka Sutra — authentication, JWT, and authorization
5
+ Project-URL: Homepage, https://vivekasutra.com/
6
+ Project-URL: Source, https://github.com/vivekasutra/viveka-mula
7
+ Keywords: security,auth,jwt,authentication,viveka,vs
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: Other/Proprietary License
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Classifier: Framework :: AsyncIO
16
+ Classifier: Typing :: Typed
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: pydantic>=2.0
20
+ Requires-Dist: pyjwt>=2.8
21
+ Requires-Dist: bcrypt>=4.0
22
+ Requires-Dist: vs-common
23
+ Provides-Extra: fastapi
24
+ Requires-Dist: fastapi>=0.110; extra == "fastapi"
25
+ Provides-Extra: dev
26
+ Requires-Dist: build; extra == "dev"
27
+ Requires-Dist: twine; extra == "dev"
28
+ Requires-Dist: pytest>=8.0; extra == "dev"
29
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
@@ -0,0 +1,53 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vs-security"
7
+ version = "0.1.0"
8
+ description = "Security library for Viveka Sutra — authentication, JWT, and authorization"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { file = "LICENSE.txt" }
12
+ keywords = ["security", "auth", "jwt", "authentication", "viveka", "vs"]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "License :: Other/Proprietary License",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Topic :: Software Development :: Libraries :: Python Modules",
21
+ "Framework :: AsyncIO",
22
+ "Typing :: Typed",
23
+ ]
24
+
25
+ dependencies = [
26
+ "pydantic>=2.0",
27
+ "pyjwt>=2.8",
28
+ "bcrypt>=4.0",
29
+ "vs-common",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ fastapi = [
34
+ "fastapi>=0.110",
35
+ ]
36
+ dev = [
37
+ "build",
38
+ "twine",
39
+ "pytest>=8.0",
40
+ "pytest-asyncio>=0.23",
41
+ ]
42
+
43
+ [project.urls]
44
+ Homepage = "https://vivekasutra.com/"
45
+ Source = "https://github.com/vivekasutra/viveka-mula"
46
+
47
+ [tool.setuptools.packages.find]
48
+ where = ["."]
49
+ include = ["vs_security*"]
50
+ exclude = [".venv*"]
51
+
52
+ [tool.setuptools.package-data]
53
+ vs_security = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,37 @@
1
+ from vs_security.schema.vs_auth_metadata import VsAuthMetadata
2
+ from vs_security.schema.vs_auth_context import VsAuthContext
3
+ from vs_security.schema.vs_credentials import VsCredentials, VsUsernamePasswordCredentials
4
+ from vs_security.schema.vs_token_pair import VsTokenPair
5
+ from vs_security.auth.vs_token_store import VsTokenStore
6
+ from vs_security.auth.vs_auth_provider import VsAuthProvider
7
+ from vs_security.auth.vs_jwt_provider import VsJWTProvider
8
+ from vs_security.auth.vs_auth_manager import VsAuthManager
9
+ from vs_security.auth.vs_username_password_provider import VsUsernamePasswordAuthProvider
10
+ from vs_security.guard.vs_security import VsSecurity, get_auth_context
11
+ from vs_security.error.vs_auth_error import (
12
+ VsAuthenticationError,
13
+ VsTokenExpiredError,
14
+ VsInsufficientRolesError,
15
+ VsInvalidCredentialsError,
16
+ VsTokenRevokedError,
17
+ )
18
+
19
+ __all__ = [
20
+ "VsAuthMetadata",
21
+ "VsAuthContext",
22
+ "VsCredentials",
23
+ "VsUsernamePasswordCredentials",
24
+ "VsTokenPair",
25
+ "VsTokenStore",
26
+ "VsAuthProvider",
27
+ "VsJWTProvider",
28
+ "VsAuthManager",
29
+ "VsUsernamePasswordAuthProvider",
30
+ "VsSecurity",
31
+ "get_auth_context",
32
+ "VsAuthenticationError",
33
+ "VsTokenExpiredError",
34
+ "VsInsufficientRolesError",
35
+ "VsInvalidCredentialsError",
36
+ "VsTokenRevokedError",
37
+ ]
@@ -0,0 +1,13 @@
1
+ from vs_security.auth.vs_auth_provider import VsAuthProvider
2
+ from vs_security.auth.vs_token_store import VsTokenStore
3
+ from vs_security.auth.vs_jwt_provider import VsJWTProvider
4
+ from vs_security.auth.vs_auth_manager import VsAuthManager
5
+ from vs_security.auth.vs_username_password_provider import VsUsernamePasswordAuthProvider
6
+
7
+ __all__ = [
8
+ "VsAuthProvider",
9
+ "VsTokenStore",
10
+ "VsJWTProvider",
11
+ "VsAuthManager",
12
+ "VsUsernamePasswordAuthProvider",
13
+ ]
@@ -0,0 +1,25 @@
1
+ from vs_common.log.vs_log_manager import VsLogManager
2
+ from vs_security.auth.vs_auth_provider import VsAuthProvider
3
+ from vs_security.auth.vs_jwt_provider import VsJWTProvider
4
+ from vs_security.schema.vs_auth_context import VsAuthContext
5
+ from vs_security.schema.vs_credentials import VsCredentials
6
+ from vs_security.schema.vs_token_pair import VsTokenPair
7
+
8
+
9
+ class VsAuthManager:
10
+
11
+ def __init__(self, jwt_provider: VsJWTProvider):
12
+ self._jwt_provider = jwt_provider
13
+ self._providers: dict[str, VsAuthProvider] = {}
14
+ self._logger = VsLogManager.get_instance(self.__class__.__name__)
15
+
16
+ def register(self, name: str, provider: VsAuthProvider) -> None:
17
+ self._providers[name] = provider
18
+ self._logger.info(f"Registered auth provider: {name}")
19
+
20
+ async def authenticate(self, provider_name: str, credentials: VsCredentials) -> VsTokenPair:
21
+ provider = self._providers.get(provider_name)
22
+ if not provider:
23
+ raise ValueError(f"No auth provider registered with name: {provider_name}")
24
+ context: VsAuthContext = await provider.authenticate(credentials)
25
+ return await self._jwt_provider.generate_token(context)
@@ -0,0 +1,10 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from vs_security.schema.vs_auth_context import VsAuthContext
4
+ from vs_security.schema.vs_credentials import VsCredentials
5
+
6
+
7
+ class VsAuthProvider(ABC):
8
+
9
+ @abstractmethod
10
+ async def authenticate(self, credentials: VsCredentials) -> VsAuthContext: ...
@@ -0,0 +1,100 @@
1
+ from datetime import datetime, timedelta, timezone
2
+ from typing import Optional
3
+ from uuid import UUID
4
+
5
+ import jwt
6
+
7
+ from vs_common.config.vs_base_config import VsBaseConfig
8
+ from vs_common.log.vs_log_manager import VsLogManager
9
+ from vs_security.auth.vs_token_store import VsTokenStore
10
+ from vs_security.error.vs_auth_error import VsTokenExpiredError, VsAuthenticationError, VsTokenRevokedError
11
+ from vs_security.schema.vs_auth_context import VsAuthContext
12
+ from vs_security.schema.vs_token_pair import VsTokenPair
13
+
14
+ _DEFAULT_ALGORITHM = "HS256"
15
+ _DEFAULT_ACCESS_EXPIRY_MINUTES = 15
16
+ _DEFAULT_REFRESH_EXPIRY_DAYS = 7
17
+
18
+
19
+ class VsJWTProvider:
20
+
21
+ def __init__(self, config: VsBaseConfig, token_store: Optional[VsTokenStore] = None):
22
+ self._logger = VsLogManager.get_instance(self.__class__.__name__)
23
+ self._token_store = token_store
24
+ self._secret = config.get("auth.secret_key")
25
+ self._algorithm = config.get("auth.algorithm", default=_DEFAULT_ALGORITHM)
26
+ self._access_expiry_minutes = config.get(
27
+ "auth.access_expiry_minutes", default=_DEFAULT_ACCESS_EXPIRY_MINUTES, data_type=int
28
+ )
29
+ self._refresh_expiry_days = config.get(
30
+ "auth.refresh_expiry_days", default=_DEFAULT_REFRESH_EXPIRY_DAYS, data_type=int
31
+ )
32
+ if not self._secret:
33
+ raise ValueError("auth.secret_key must be set in config.ini")
34
+
35
+ async def generate_token(self, context: VsAuthContext) -> VsTokenPair:
36
+ access_token = self._mint(context, self._access_expiry_minutes * 60, "access")
37
+ refresh_token = self._mint(context, self._refresh_expiry_days * 86400, "refresh")
38
+ if self._token_store:
39
+ await self._token_store.save(context.user_id, refresh_token)
40
+ self._logger.debug(f"Generated token pair for user {context.user_id}")
41
+ return VsTokenPair(access_token=access_token, refresh_token=refresh_token)
42
+
43
+ async def verify_token(self, token: str) -> VsAuthContext:
44
+ payload = self._decode(token, expected_type="access")
45
+ return self._payload_to_context(payload)
46
+
47
+ async def refresh_token(self, refresh_token: str) -> VsTokenPair:
48
+ payload = self._decode(refresh_token, expected_type="refresh")
49
+ user_id = UUID(payload["sub"])
50
+
51
+ if self._token_store:
52
+ stored = await self._token_store.get_all(user_id)
53
+ if refresh_token not in stored:
54
+ raise VsTokenRevokedError()
55
+ await self._token_store.delete(user_id, refresh_token)
56
+
57
+ context = self._payload_to_context(payload)
58
+ return await self.generate_token(context)
59
+
60
+ async def revoke_token(self, user_id: UUID, refresh_token: str) -> None:
61
+ if not self._token_store:
62
+ raise NotImplementedError("No VsTokenStore configured")
63
+ await self._token_store.delete(user_id, refresh_token)
64
+
65
+ async def revoke_all_tokens(self, user_id: UUID) -> None:
66
+ if not self._token_store:
67
+ raise NotImplementedError("No VsTokenStore configured")
68
+ await self._token_store.delete_all(user_id)
69
+
70
+ def _mint(self, context: VsAuthContext, expiry_seconds: int, token_type: str) -> str:
71
+ now = datetime.now(timezone.utc)
72
+ payload = {
73
+ "sub": str(context.user_id),
74
+ "username": context.username,
75
+ "roles": context.roles,
76
+ "provider": context.provider,
77
+ "type": token_type,
78
+ "iat": now,
79
+ "exp": now + timedelta(seconds=expiry_seconds),
80
+ }
81
+ return jwt.encode(payload, self._secret, algorithm=self._algorithm)
82
+
83
+ def _decode(self, token: str, expected_type: str) -> dict:
84
+ try:
85
+ payload = jwt.decode(token, self._secret, algorithms=[self._algorithm])
86
+ if payload.get("type") != expected_type:
87
+ raise VsAuthenticationError(f"Expected {expected_type} token")
88
+ return payload
89
+ except jwt.ExpiredSignatureError:
90
+ raise VsTokenExpiredError()
91
+ except jwt.InvalidTokenError as e:
92
+ raise VsAuthenticationError(f"Invalid token: {e}")
93
+
94
+ def _payload_to_context(self, payload: dict) -> VsAuthContext:
95
+ return VsAuthContext(
96
+ user_id=UUID(payload["sub"]),
97
+ username=payload["username"],
98
+ roles=payload.get("roles", []),
99
+ provider=payload.get("provider", ""),
100
+ )
@@ -0,0 +1,18 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import List
3
+ from uuid import UUID
4
+
5
+
6
+ class VsTokenStore(ABC):
7
+
8
+ @abstractmethod
9
+ async def save(self, user_id: UUID, refresh_token: str) -> None: ...
10
+
11
+ @abstractmethod
12
+ async def get_all(self, user_id: UUID) -> List[str]: ...
13
+
14
+ @abstractmethod
15
+ async def delete(self, user_id: UUID, refresh_token: str) -> None: ...
16
+
17
+ @abstractmethod
18
+ async def delete_all(self, user_id: UUID) -> None: ...
@@ -0,0 +1,39 @@
1
+ from typing import Awaitable, Callable, Tuple
2
+
3
+ import bcrypt
4
+
5
+ from vs_common.log.vs_log_manager import VsLogManager
6
+ from vs_security.auth.vs_auth_provider import VsAuthProvider
7
+ from vs_security.auth.vs_jwt_provider import VsJWTProvider
8
+ from vs_security.error.vs_auth_error import VsInvalidCredentialsError
9
+ from vs_security.schema.vs_auth_context import VsAuthContext
10
+ from vs_security.schema.vs_credentials import VsCredentials, VsUsernamePasswordCredentials
11
+ from vs_security.schema.vs_token_pair import VsTokenPair
12
+
13
+
14
+ class VsUsernamePasswordAuthProvider(VsAuthProvider):
15
+
16
+ def __init__(
17
+ self,
18
+ jwt_provider: VsJWTProvider,
19
+ user_loader: Callable[[str], Awaitable[Tuple[VsAuthContext, str]]],
20
+ ):
21
+ self._jwt_provider = jwt_provider
22
+ self._user_loader = user_loader
23
+ self._logger = VsLogManager.get_instance(self.__class__.__name__)
24
+
25
+ async def authenticate(self, credentials: VsCredentials) -> VsAuthContext:
26
+ if not isinstance(credentials, VsUsernamePasswordCredentials):
27
+ raise TypeError("Expected VsUsernamePasswordCredentials")
28
+
29
+ result = await self._user_loader(credentials.username)
30
+ if result is None:
31
+ raise VsInvalidCredentialsError()
32
+
33
+ context, hashed_password = result
34
+
35
+ if not bcrypt.checkpw(credentials.password.encode(), hashed_password.encode()):
36
+ raise VsInvalidCredentialsError()
37
+
38
+ self._logger.debug(f"Authenticated user {credentials.username}")
39
+ return context
@@ -0,0 +1,15 @@
1
+ from vs_security.error.vs_auth_error import (
2
+ VsAuthenticationError,
3
+ VsTokenExpiredError,
4
+ VsInsufficientRolesError,
5
+ VsInvalidCredentialsError,
6
+ VsTokenRevokedError,
7
+ )
8
+
9
+ __all__ = [
10
+ "VsAuthenticationError",
11
+ "VsTokenExpiredError",
12
+ "VsInsufficientRolesError",
13
+ "VsInvalidCredentialsError",
14
+ "VsTokenRevokedError",
15
+ ]
@@ -0,0 +1,25 @@
1
+ class VsAuthenticationError(Exception):
2
+ def __init__(self, message: str = "Authentication failed"):
3
+ super().__init__(message)
4
+ self.message = message
5
+
6
+
7
+ class VsTokenExpiredError(VsAuthenticationError):
8
+ def __init__(self):
9
+ super().__init__("Token has expired")
10
+
11
+
12
+ class VsInsufficientRolesError(VsAuthenticationError):
13
+ def __init__(self, required: list):
14
+ super().__init__(f"Required roles not present: {required}")
15
+ self.required = required
16
+
17
+
18
+ class VsInvalidCredentialsError(VsAuthenticationError):
19
+ def __init__(self):
20
+ super().__init__("Invalid username or password")
21
+
22
+
23
+ class VsTokenRevokedError(VsAuthenticationError):
24
+ def __init__(self):
25
+ super().__init__("Token has been revoked")
@@ -0,0 +1,6 @@
1
+ from vs_security.guard.vs_security import VsSecurity, get_auth_context
2
+
3
+ __all__ = [
4
+ "VsSecurity",
5
+ "get_auth_context",
6
+ ]
@@ -0,0 +1,42 @@
1
+ from contextvars import ContextVar
2
+ from typing import List, Optional
3
+
4
+ from fastapi import Depends
5
+ from fastapi.exceptions import HTTPException
6
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
7
+
8
+ from vs_security.auth.vs_jwt_provider import VsJWTProvider
9
+ from vs_security.error.vs_auth_error import VsAuthenticationError, VsInsufficientRolesError
10
+ from vs_security.schema.vs_auth_context import VsAuthContext
11
+
12
+ _bearer = HTTPBearer()
13
+
14
+ _auth_context_var: ContextVar[Optional[VsAuthContext]] = ContextVar("auth_context", default=None)
15
+
16
+
17
+ def get_auth_context() -> Optional[VsAuthContext]:
18
+ return _auth_context_var.get()
19
+
20
+
21
+ class VsSecurity:
22
+
23
+ def __init__(self, jwt_provider: VsJWTProvider, roles: Optional[List[str]] = None):
24
+ self._jwt_provider = jwt_provider
25
+ self._roles = roles or []
26
+
27
+ async def __call__(
28
+ self, credentials: HTTPAuthorizationCredentials = Depends(_bearer)
29
+ ) -> VsAuthContext:
30
+ try:
31
+ context = await self._jwt_provider.verify_token(credentials.credentials)
32
+ except VsAuthenticationError as e:
33
+ raise HTTPException(status_code=401, detail=str(e))
34
+
35
+ if self._roles and not context.has_any_role(*self._roles):
36
+ raise HTTPException(
37
+ status_code=403,
38
+ detail=f"Required roles: {self._roles}",
39
+ )
40
+
41
+ _auth_context_var.set(context)
42
+ return context
@@ -0,0 +1,43 @@
1
+ from typing import List, Optional
2
+
3
+ from vs_security.guard.vs_security import VsSecurity
4
+
5
+
6
+ class VsSecurityFactory:
7
+
8
+ _instance: Optional[VsSecurity] = None
9
+ _jwt_provider = None
10
+
11
+ @classmethod
12
+ def init(cls, secret_key: str, algorithm: str = "HS256", roles: Optional[List[str]] = None) -> None:
13
+ from vs_security.auth.vs_jwt_provider import VsJWTProvider
14
+
15
+ class _InlineConfig:
16
+ def get(self, key, default=None, data_type=str):
17
+ if key == "auth.secret_key":
18
+ return secret_key
19
+ if key == "auth.algorithm":
20
+ return algorithm
21
+ return default
22
+
23
+ def get_section(self, section):
24
+ return {}
25
+
26
+ cls._jwt_provider = VsJWTProvider(config=_InlineConfig())
27
+ cls._instance = VsSecurity(jwt_provider=cls._jwt_provider, roles=roles)
28
+
29
+ @classmethod
30
+ def get(cls) -> VsSecurity:
31
+ if cls._instance is None:
32
+ raise RuntimeError(
33
+ "VsSecurityFactory not initialized. Call VsSecurityFactory.init() at startup."
34
+ )
35
+ return cls._instance
36
+
37
+ @classmethod
38
+ def with_roles(cls, roles: List[str]) -> VsSecurity:
39
+ if cls._jwt_provider is None:
40
+ raise RuntimeError(
41
+ "VsSecurityFactory not initialized. Call VsSecurityFactory.init() at startup."
42
+ )
43
+ return VsSecurity(jwt_provider=cls._jwt_provider, roles=roles)
@@ -0,0 +1,12 @@
1
+ from vs_security.schema.vs_auth_metadata import VsAuthMetadata
2
+ from vs_security.schema.vs_auth_context import VsAuthContext
3
+ from vs_security.schema.vs_credentials import VsCredentials, VsUsernamePasswordCredentials
4
+ from vs_security.schema.vs_token_pair import VsTokenPair
5
+
6
+ __all__ = [
7
+ "VsAuthMetadata",
8
+ "VsAuthContext",
9
+ "VsCredentials",
10
+ "VsUsernamePasswordCredentials",
11
+ "VsTokenPair",
12
+ ]
@@ -0,0 +1,23 @@
1
+ from typing import List
2
+ from uuid import UUID
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from vs_security.schema.vs_auth_metadata import VsAuthMetadata
7
+
8
+
9
+ class VsAuthContext(BaseModel):
10
+ user_id: UUID
11
+ username: str
12
+ roles: List[str] = []
13
+ provider: str
14
+ metadata: VsAuthMetadata = VsAuthMetadata()
15
+
16
+ def has_role(self, role: str) -> bool:
17
+ return role in self.roles
18
+
19
+ def has_any_role(self, *roles: str) -> bool:
20
+ return any(r in self.roles for r in roles)
21
+
22
+ def has_all_roles(self, *roles: str) -> bool:
23
+ return all(r in self.roles for r in roles)
@@ -0,0 +1,5 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class VsAuthMetadata(BaseModel):
5
+ pass
@@ -0,0 +1,10 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class VsCredentials(BaseModel):
5
+ pass
6
+
7
+
8
+ class VsUsernamePasswordCredentials(VsCredentials):
9
+ username: str
10
+ password: str
@@ -0,0 +1,6 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class VsTokenPair(BaseModel):
5
+ access_token: str
6
+ refresh_token: str
@@ -0,0 +1,29 @@
1
+ Metadata-Version: 2.4
2
+ Name: vs-security
3
+ Version: 0.1.0
4
+ Summary: Security library for Viveka Sutra — authentication, JWT, and authorization
5
+ Project-URL: Homepage, https://vivekasutra.com/
6
+ Project-URL: Source, https://github.com/vivekasutra/viveka-mula
7
+ Keywords: security,auth,jwt,authentication,viveka,vs
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: Other/Proprietary License
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Classifier: Framework :: AsyncIO
16
+ Classifier: Typing :: Typed
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: pydantic>=2.0
20
+ Requires-Dist: pyjwt>=2.8
21
+ Requires-Dist: bcrypt>=4.0
22
+ Requires-Dist: vs-common
23
+ Provides-Extra: fastapi
24
+ Requires-Dist: fastapi>=0.110; extra == "fastapi"
25
+ Provides-Extra: dev
26
+ Requires-Dist: build; extra == "dev"
27
+ Requires-Dist: twine; extra == "dev"
28
+ Requires-Dist: pytest>=8.0; extra == "dev"
29
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
@@ -0,0 +1,23 @@
1
+ pyproject.toml
2
+ vs_security/__init__.py
3
+ vs_security.egg-info/PKG-INFO
4
+ vs_security.egg-info/SOURCES.txt
5
+ vs_security.egg-info/dependency_links.txt
6
+ vs_security.egg-info/requires.txt
7
+ vs_security.egg-info/top_level.txt
8
+ vs_security/auth/__init__.py
9
+ vs_security/auth/vs_auth_manager.py
10
+ vs_security/auth/vs_auth_provider.py
11
+ vs_security/auth/vs_jwt_provider.py
12
+ vs_security/auth/vs_token_store.py
13
+ vs_security/auth/vs_username_password_provider.py
14
+ vs_security/error/__init__.py
15
+ vs_security/error/vs_auth_error.py
16
+ vs_security/guard/__init__.py
17
+ vs_security/guard/vs_security.py
18
+ vs_security/guard/vs_security_factory.py
19
+ vs_security/schema/__init__.py
20
+ vs_security/schema/vs_auth_context.py
21
+ vs_security/schema/vs_auth_metadata.py
22
+ vs_security/schema/vs_credentials.py
23
+ vs_security/schema/vs_token_pair.py
@@ -0,0 +1,13 @@
1
+ pydantic>=2.0
2
+ pyjwt>=2.8
3
+ bcrypt>=4.0
4
+ vs-common
5
+
6
+ [dev]
7
+ build
8
+ twine
9
+ pytest>=8.0
10
+ pytest-asyncio>=0.23
11
+
12
+ [fastapi]
13
+ fastapi>=0.110
@@ -0,0 +1 @@
1
+ vs_security