auth-gate 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,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.4
2
+ Name: auth-gate
3
+ Version: 0.1.0
4
+ Summary: Enterprise-grade authentication for microservices with Kong and Keycloak integration
5
+ Home-page: https://github.com/tradelink-org/auth-gate
6
+ Author: Brian Mburu
7
+ Author-email: Brian Mburu <brian.mburu@students.jkuat.ac.ke>
8
+ Maintainer-email: Brian Mburu <brian.mburu@students.jkuat.ac.ke>
9
+ License: MIT
10
+ Project-URL: Homepage, https://github.com/tradelink-org/auth-gate
11
+ Project-URL: Repository, https://github.com/tradelink-org/auth-gate.git
12
+ Project-URL: Documentation, https://github.com/tradelink-org/auth-gate.git
13
+ Project-URL: Bug Tracker, https://github.com/tradelink-org/auth-gate/issues
14
+ Keywords: authentication,keycloak,kong,fastapi,microservices
15
+ Classifier: Development Status :: 5 - Production/Stable
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
23
+ Classifier: Framework :: FastAPI
24
+ Requires-Python: >=3.11
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: fastapi>=0.109.0
28
+ Requires-Dist: pydantic>=2.5.0
29
+ Requires-Dist: pydantic-settings>=2.1.0
30
+ Requires-Dist: httpx>=0.26.0
31
+ Requires-Dist: python-jose[cryptography]>=3.3.0
32
+ Requires-Dist: starlette>=0.35.0
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
35
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
36
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
37
+ Requires-Dist: black>=23.0.0; extra == "dev"
38
+ Requires-Dist: mypy>=1.7.0; extra == "dev"
39
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
40
+ Dynamic: license-file
41
+
42
+ # Auth Gate
43
+
44
+ Enterprise-grade authentication for microservices with Kong and Keycloak integration.
45
+
46
+ ## Features
47
+
48
+ - **Dual-mode authentication**: Support for both Kong header-based auth (production) and direct Keycloak validation (development)
49
+ - **Service-to-service authentication**: Built-in client credentials flow for secure inter-service communication
50
+ - **Circuit breaker pattern**: Resilient handling of Keycloak failures with automatic recovery
51
+ - **FastAPI integration**: Ready-to-use dependencies for protecting endpoints
52
+ - **Role-based access control**: Fine-grained permission management with role and scope validation
53
+ - **Middleware support**: Automatic request authentication with configurable exclusions
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ pip install auth-gate
59
+
60
+ ```
61
+
62
+ ### For Development
63
+
64
+ ```bash
65
+ pip install auth-gate[dev]
66
+
67
+ ```
68
+
69
+ ## Quick Start
70
+
71
+ ### Basic Usage
72
+
73
+ ```py
74
+ from fastapi import FastAPI, Depends
75
+ from auth_gate import (
76
+ AuthMiddleware,
77
+ get_current_user,
78
+ require_admin,
79
+ UserContext,
80
+ AuthSettings
81
+ )
82
+
83
+ # Initialize FastAPI app
84
+ app = FastAPI()
85
+
86
+ # Add authentication middleware
87
+ app.add_middleware(
88
+ AuthMiddleware,
89
+ excluded_paths={"/health", "/metrics"},
90
+ excluded_prefixes={"/docs", "/openapi.json"}
91
+ )
92
+
93
+ # Protected endpoint - requires authentication
94
+ @app.get("/api/profile")
95
+ async def get_profile(user: UserContext = Depends(get_current_user)):
96
+ return {
97
+ "user_id": user.user_id,
98
+ "username": user.username,
99
+ "roles": user.roles
100
+ }
101
+
102
+ # Admin-only endpoint
103
+ @app.get("/api/admin/users")
104
+ async def list_users(admin: UserContext = Depends(require_admin)):
105
+ return {"message": "Admin access granted"}
106
+
107
+ # Role-based access
108
+ from auth_gate import require_roles
109
+
110
+ require_supplier_or_admin = require_roles("supplier", "admin")
111
+
112
+ @app.get("/api/products")
113
+ async def list_products(user: UserContext = Depends(require_supplier_or_admin)):
114
+ return {"products": []}
115
+ ```
116
+
117
+ ### Service-to-service Auth
118
+
119
+ ```py
120
+ from auth_gate import ServiceAuthClient
121
+ import httpx
122
+
123
+ # Get service auth client
124
+ auth_client = ServiceAuthClient()
125
+
126
+ # Make authenticated service call
127
+ async def call_other_service():
128
+ # Get service token (automatically cached and refreshed)
129
+ auth_header = await auth_client.get_service_token()
130
+
131
+ async with httpx.AsyncClient() as client:
132
+ response = await client.get(
133
+ "http://other-service/api/data",
134
+ headers={"Authorization": auth_header}
135
+ )
136
+ return response.json()
137
+ ```
138
+
139
+ ## Configuration
140
+
141
+ Configure via envirinment variables:
142
+
143
+ ```bash
144
+ # Authentication mode
145
+ AUTH_MODE=kong_headers # or "direct_keycloak", "bypass" (testing only)
146
+
147
+ # Keycloak settings
148
+ KEYCLOAK_REALM_URL=https://keycloak.example.com/realms/tradelink
149
+ KEYCLOAK_CLIENT_ID=my-service
150
+ KEYCLOAK_CLIENT_SECRET=secret
151
+
152
+ # Service account (for S2S auth)
153
+ SERVICE_CLIENT_ID=my-service-account
154
+ SERVICE_CLIENT_SECRET=secret
155
+
156
+ # Optional settings
157
+ VERIFY_HMAC=false
158
+ INTERNAL_HMAC_KEY=your-hmac-key
159
+ ```
160
+
161
+ ## Advanced Features
162
+
163
+ ### Custom Excluded Paths
164
+
165
+ ```py
166
+ app.add_middleware(
167
+ AuthMiddleware,
168
+ excluded_paths={"/health", "/metrics", "/public"},
169
+ excluded_prefixes={"/static", "/docs"},
170
+ optional_auth_paths={"/api/products"} # Auth optional for these paths
171
+ )
172
+ ```
173
+
174
+ ### Direct Validator Usage
175
+
176
+ ```py
177
+ from auth_gate import UserValidator, AuthMode
178
+
179
+ validator = UserValidator(mode=AuthMode.DIRECT_KEYCLOAK)
180
+ user_context = await validator.validate_keycloak_token(token)
181
+ ```
182
+
183
+ ### Circuit Breaker Configuration
184
+
185
+ The S2S auth client includes automatic circuit breaker protection:
186
+
187
+ - Opens after 5 consecutive failures
188
+ - Attempts recovery after 60 seconds
189
+ - Provides fail-fast behavior when Keycloak is unavailable
190
+
191
+ ## Development
192
+
193
+ ### Running Tests
194
+
195
+ ```bash
196
+ pytest tests/ --cov=auth_gate
197
+ ```
198
+
199
+ ### Code quality
200
+
201
+ ```bash
202
+ black src/
203
+ ruff check src/
204
+ mypy src/
205
+ ```
206
+
207
+ ## License
208
+
209
+ For use within tradelink suite of services - See LICENSE file for details.
210
+
211
+ ## Support
212
+
213
+ For issues and questions, please use the [GitHub issue tracker](https://github.com/tradelink-org/auth-gate/issues).
@@ -0,0 +1,172 @@
1
+ # Auth Gate
2
+
3
+ Enterprise-grade authentication for microservices with Kong and Keycloak integration.
4
+
5
+ ## Features
6
+
7
+ - **Dual-mode authentication**: Support for both Kong header-based auth (production) and direct Keycloak validation (development)
8
+ - **Service-to-service authentication**: Built-in client credentials flow for secure inter-service communication
9
+ - **Circuit breaker pattern**: Resilient handling of Keycloak failures with automatic recovery
10
+ - **FastAPI integration**: Ready-to-use dependencies for protecting endpoints
11
+ - **Role-based access control**: Fine-grained permission management with role and scope validation
12
+ - **Middleware support**: Automatic request authentication with configurable exclusions
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install auth-gate
18
+
19
+ ```
20
+
21
+ ### For Development
22
+
23
+ ```bash
24
+ pip install auth-gate[dev]
25
+
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### Basic Usage
31
+
32
+ ```py
33
+ from fastapi import FastAPI, Depends
34
+ from auth_gate import (
35
+ AuthMiddleware,
36
+ get_current_user,
37
+ require_admin,
38
+ UserContext,
39
+ AuthSettings
40
+ )
41
+
42
+ # Initialize FastAPI app
43
+ app = FastAPI()
44
+
45
+ # Add authentication middleware
46
+ app.add_middleware(
47
+ AuthMiddleware,
48
+ excluded_paths={"/health", "/metrics"},
49
+ excluded_prefixes={"/docs", "/openapi.json"}
50
+ )
51
+
52
+ # Protected endpoint - requires authentication
53
+ @app.get("/api/profile")
54
+ async def get_profile(user: UserContext = Depends(get_current_user)):
55
+ return {
56
+ "user_id": user.user_id,
57
+ "username": user.username,
58
+ "roles": user.roles
59
+ }
60
+
61
+ # Admin-only endpoint
62
+ @app.get("/api/admin/users")
63
+ async def list_users(admin: UserContext = Depends(require_admin)):
64
+ return {"message": "Admin access granted"}
65
+
66
+ # Role-based access
67
+ from auth_gate import require_roles
68
+
69
+ require_supplier_or_admin = require_roles("supplier", "admin")
70
+
71
+ @app.get("/api/products")
72
+ async def list_products(user: UserContext = Depends(require_supplier_or_admin)):
73
+ return {"products": []}
74
+ ```
75
+
76
+ ### Service-to-service Auth
77
+
78
+ ```py
79
+ from auth_gate import ServiceAuthClient
80
+ import httpx
81
+
82
+ # Get service auth client
83
+ auth_client = ServiceAuthClient()
84
+
85
+ # Make authenticated service call
86
+ async def call_other_service():
87
+ # Get service token (automatically cached and refreshed)
88
+ auth_header = await auth_client.get_service_token()
89
+
90
+ async with httpx.AsyncClient() as client:
91
+ response = await client.get(
92
+ "http://other-service/api/data",
93
+ headers={"Authorization": auth_header}
94
+ )
95
+ return response.json()
96
+ ```
97
+
98
+ ## Configuration
99
+
100
+ Configure via envirinment variables:
101
+
102
+ ```bash
103
+ # Authentication mode
104
+ AUTH_MODE=kong_headers # or "direct_keycloak", "bypass" (testing only)
105
+
106
+ # Keycloak settings
107
+ KEYCLOAK_REALM_URL=https://keycloak.example.com/realms/tradelink
108
+ KEYCLOAK_CLIENT_ID=my-service
109
+ KEYCLOAK_CLIENT_SECRET=secret
110
+
111
+ # Service account (for S2S auth)
112
+ SERVICE_CLIENT_ID=my-service-account
113
+ SERVICE_CLIENT_SECRET=secret
114
+
115
+ # Optional settings
116
+ VERIFY_HMAC=false
117
+ INTERNAL_HMAC_KEY=your-hmac-key
118
+ ```
119
+
120
+ ## Advanced Features
121
+
122
+ ### Custom Excluded Paths
123
+
124
+ ```py
125
+ app.add_middleware(
126
+ AuthMiddleware,
127
+ excluded_paths={"/health", "/metrics", "/public"},
128
+ excluded_prefixes={"/static", "/docs"},
129
+ optional_auth_paths={"/api/products"} # Auth optional for these paths
130
+ )
131
+ ```
132
+
133
+ ### Direct Validator Usage
134
+
135
+ ```py
136
+ from auth_gate import UserValidator, AuthMode
137
+
138
+ validator = UserValidator(mode=AuthMode.DIRECT_KEYCLOAK)
139
+ user_context = await validator.validate_keycloak_token(token)
140
+ ```
141
+
142
+ ### Circuit Breaker Configuration
143
+
144
+ The S2S auth client includes automatic circuit breaker protection:
145
+
146
+ - Opens after 5 consecutive failures
147
+ - Attempts recovery after 60 seconds
148
+ - Provides fail-fast behavior when Keycloak is unavailable
149
+
150
+ ## Development
151
+
152
+ ### Running Tests
153
+
154
+ ```bash
155
+ pytest tests/ --cov=auth_gate
156
+ ```
157
+
158
+ ### Code quality
159
+
160
+ ```bash
161
+ black src/
162
+ ruff check src/
163
+ mypy src/
164
+ ```
165
+
166
+ ## License
167
+
168
+ For use within tradelink suite of services - See LICENSE file for details.
169
+
170
+ ## Support
171
+
172
+ For issues and questions, please use the [GitHub issue tracker](https://github.com/tradelink-org/auth-gate/issues).
@@ -0,0 +1,75 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "auth-gate"
7
+ version = "0.1.0"
8
+ description = "Enterprise-grade authentication for microservices with Kong and Keycloak integration"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Brian Mburu", email = "brian.mburu@students.jkuat.ac.ke"}
14
+ ]
15
+ maintainers = [
16
+ {name = "Brian Mburu", email = "brian.mburu@students.jkuat.ac.ke"}
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 5 - Production/Stable",
20
+ "Intended Audience :: Developers",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ "Topic :: Internet :: WWW/HTTP :: HTTP Servers",
27
+ "Framework :: FastAPI",
28
+ ]
29
+ keywords = ["authentication", "keycloak", "kong", "fastapi", "microservices"]
30
+
31
+ dependencies = [
32
+ "fastapi>=0.109.0",
33
+ "pydantic>=2.5.0",
34
+ "pydantic-settings>=2.1.0",
35
+ "httpx>=0.26.0",
36
+ "python-jose[cryptography]>=3.3.0",
37
+ "starlette>=0.35.0",
38
+ ]
39
+
40
+ [project.optional-dependencies]
41
+ dev = [
42
+ "pytest>=7.4.0",
43
+ "pytest-asyncio>=0.21.0",
44
+ "pytest-cov>=4.1.0",
45
+ "black>=23.0.0",
46
+ "mypy>=1.7.0",
47
+ "ruff>=0.1.0",
48
+ ]
49
+
50
+ [project.urls]
51
+ Homepage = "https://github.com/tradelink-org/auth-gate"
52
+ Repository = "https://github.com/tradelink-org/auth-gate.git"
53
+ Documentation = "https://github.com/tradelink-org/auth-gate.git"
54
+ "Bug Tracker" = "https://github.com/tradelink-org/auth-gate/issues"
55
+
56
+ [tool.setuptools]
57
+ package-dir = {"" = "src"}
58
+
59
+ [tool.setuptools.packages.find]
60
+ where = ["src"]
61
+
62
+ [tool.black]
63
+ line-length = 100
64
+ target-version = ["py311"]
65
+
66
+ [tool.ruff]
67
+ line-length = 100
68
+ select = ["E", "F", "I", "N", "W"]
69
+ ignore = ["E501"]
70
+
71
+ [tool.mypy]
72
+ python_version = "3.11"
73
+ warn_return_any = true
74
+ warn_unused_configs = true
75
+ ignore_missing_imports = true
@@ -0,0 +1,49 @@
1
+ [metadata]
2
+ name = auth-gate
3
+ version = 0.1.0
4
+ author = Brian Mburu
5
+ author_email = brian.mburu@students.jkuat.ac.ke
6
+ description = Enterprise-grade authentication for microservices with Kong and Keycloak integration
7
+ long_description = file: README.md
8
+ long_description_content_type = text/markdown
9
+ url = https://github.com/tradelink-org/auth-gate
10
+ project_urls =
11
+ Bug Tracker = https://github.com/tradelink-org/auth-gate/issues
12
+ Documentation = https://auth-client.tradelink.io
13
+ classifiers =
14
+ Programming Language :: Python :: 3
15
+ Programming Language :: Python :: 3.11
16
+ Programming Language :: Python :: 3.12
17
+ License :: OSI Approved :: MIT License
18
+ Operating System :: OS Independent
19
+ Framework :: FastAPI
20
+
21
+ [options]
22
+ package_dir =
23
+ = src
24
+ packages = find:
25
+ python_requires = >=3.11
26
+ install_requires =
27
+ fastapi>=0.109.0
28
+ pydantic>=2.5.0
29
+ pydantic-settings>=2.1.0
30
+ httpx>=0.26.0
31
+ python-jose[cryptography]>=3.3.0
32
+ starlette>=0.35.0
33
+
34
+ [options.packages.find]
35
+ where = src
36
+
37
+ [options.extras_require]
38
+ dev =
39
+ pytest>=7.4.0
40
+ pytest-asyncio>=0.21.0
41
+ pytest-cov>=4.1.0
42
+ black>=23.0.0
43
+ mypy>=1.7.0
44
+ ruff>=0.1.0
45
+
46
+ [egg_info]
47
+ tag_build =
48
+ tag_date = 0
49
+
@@ -0,0 +1,52 @@
1
+ """
2
+ Tradelink Authentication Client
3
+
4
+ Enterprise authentication client for microservices with Kong/Keycloak integration.
5
+ """
6
+
7
+ from .config import AuthMode, AuthSettings
8
+ from .fastapi_utils import (
9
+ get_current_user,
10
+ get_optional_user,
11
+ require_admin,
12
+ require_customer,
13
+ require_moderator,
14
+ require_roles,
15
+ require_scopes,
16
+ require_supplier,
17
+ require_supplier_or_admin,
18
+ verify_hmac_signature,
19
+ )
20
+ from .middleware import AuthMiddleware
21
+ from .s2s_auth import CircuitBreaker, CircuitBreakerOpenError, ServiceAuthClient
22
+ from .schemas import UserContext
23
+ from .user_auth import UserValidator
24
+
25
+ __version__ = "1.0.0"
26
+
27
+ __all__ = [
28
+ # Configuration
29
+ "AuthSettings",
30
+ "AuthMode",
31
+ # Schemas
32
+ "UserContext",
33
+ # User Authentication
34
+ "UserValidator",
35
+ # Service-to-Service
36
+ "ServiceAuthClient",
37
+ "CircuitBreaker",
38
+ "CircuitBreakerOpenError",
39
+ # Middleware
40
+ "AuthMiddleware",
41
+ # FastAPI Dependencies
42
+ "get_current_user",
43
+ "get_optional_user",
44
+ "require_roles",
45
+ "require_scopes",
46
+ "require_admin",
47
+ "require_supplier",
48
+ "require_customer",
49
+ "require_moderator",
50
+ "require_supplier_or_admin",
51
+ "verify_hmac_signature",
52
+ ]
@@ -0,0 +1,99 @@
1
+ """
2
+ Configuration management for Tradelink Auth Client
3
+ """
4
+
5
+ from enum import Enum
6
+ from typing import Optional
7
+
8
+ from pydantic_settings import BaseSettings
9
+
10
+
11
+ class AuthMode(Enum):
12
+ """Authentication modes for different environments"""
13
+
14
+ KONG_HEADERS = "kong_headers" # Production: Kong validates tokens
15
+ DIRECT_KEYCLOAK = "direct_keycloak" # Development: Direct Keycloak validation
16
+ BYPASS = "bypass" # Testing only - NEVER use in production
17
+
18
+
19
+ class AuthSettings(BaseSettings):
20
+ """
21
+ Centralized configuration for authentication client.
22
+ All settings can be overridden via environment variables.
23
+ """
24
+
25
+ model_config = {
26
+ "env_file": (".env", ".env.test", ".env.prod"),
27
+ "extra": "ignore",
28
+ "env_file_encoding": "utf-8",
29
+ "case_sensitive": True,
30
+ }
31
+
32
+ # Authentication Mode
33
+ AUTH_MODE: str = "kong_headers"
34
+
35
+ # Keycloak Configuration
36
+ KEYCLOAK_REALM_URL: str = "http://localhost:8080/realms/master"
37
+ KEYCLOAK_CLIENT_ID: str = "backend-service"
38
+ KEYCLOAK_CLIENT_SECRET: str = ""
39
+
40
+ # Service Account Configuration (for S2S)
41
+ SERVICE_CLIENT_ID: str = "service-account"
42
+ SERVICE_CLIENT_SECRET: str = ""
43
+
44
+ # HMAC Verification (optional)
45
+ VERIFY_HMAC: bool = False
46
+ INTERNAL_HMAC_KEY: str = ""
47
+
48
+ # Circuit Breaker Settings
49
+ CIRCUIT_BREAKER_FAILURE_THRESHOLD: int = 5
50
+ CIRCUIT_BREAKER_RECOVERY_TIMEOUT: int = 60
51
+
52
+ # Token Settings
53
+ TOKEN_CACHE_TTL: int = 300 # seconds
54
+ TOKEN_REFRESH_BUFFER: int = 30 # seconds before expiry
55
+
56
+ # HTTP Client Settings
57
+ HTTP_TIMEOUT: float = 10.0
58
+ HTTP_MAX_KEEPALIVE_CONNECTIONS: int = 10
59
+
60
+ @property
61
+ def auth_mode_enum(self) -> AuthMode:
62
+ """Get AUTH_MODE as enum"""
63
+ try:
64
+ return AuthMode(self.AUTH_MODE.lower())
65
+ except ValueError:
66
+ raise ValueError(f"Invalid AUTH_MODE: {self.AUTH_MODE}")
67
+
68
+ @property
69
+ def is_production(self) -> bool:
70
+ """Check if running in production mode"""
71
+ return self.auth_mode_enum == AuthMode.KONG_HEADERS
72
+
73
+ @property
74
+ def is_development(self) -> bool:
75
+ """Check if running in development mode"""
76
+ return self.auth_mode_enum == AuthMode.DIRECT_KEYCLOAK
77
+
78
+ @property
79
+ def is_testing(self) -> bool:
80
+ """Check if running in testing/bypass mode"""
81
+ return self.auth_mode_enum == AuthMode.BYPASS
82
+
83
+
84
+ # Global settings instance
85
+ _settings: Optional[AuthSettings] = None
86
+
87
+
88
+ def get_settings() -> AuthSettings:
89
+ """Get or create settings instance"""
90
+ global _settings
91
+ if _settings is None:
92
+ _settings = AuthSettings()
93
+ return _settings
94
+
95
+
96
+ def reset_settings() -> None:
97
+ """Reset settings (useful for testing)"""
98
+ global _settings
99
+ _settings = None