authix-python-sdk 1.0.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.
- authix_python_sdk-1.0.0/LICENSE +21 -0
- authix_python_sdk-1.0.0/MANIFEST.in +11 -0
- authix_python_sdk-1.0.0/PKG-INFO +666 -0
- authix_python_sdk-1.0.0/README.md +609 -0
- authix_python_sdk-1.0.0/authix/__init__.py +23 -0
- authix_python_sdk-1.0.0/authix/api.py +81 -0
- authix_python_sdk-1.0.0/authix/cli.py +252 -0
- authix_python_sdk-1.0.0/authix/client.py +110 -0
- authix_python_sdk-1.0.0/authix/decorators.py +109 -0
- authix_python_sdk-1.0.0/authix/exceptions.py +42 -0
- authix_python_sdk-1.0.0/authix/handlers.py +570 -0
- authix_python_sdk-1.0.0/authix/middleware.py +237 -0
- authix_python_sdk-1.0.0/authix_python_sdk.egg-info/PKG-INFO +666 -0
- authix_python_sdk-1.0.0/authix_python_sdk.egg-info/SOURCES.txt +20 -0
- authix_python_sdk-1.0.0/authix_python_sdk.egg-info/dependency_links.txt +1 -0
- authix_python_sdk-1.0.0/authix_python_sdk.egg-info/entry_points.txt +2 -0
- authix_python_sdk-1.0.0/authix_python_sdk.egg-info/not-zip-safe +1 -0
- authix_python_sdk-1.0.0/authix_python_sdk.egg-info/requires.txt +16 -0
- authix_python_sdk-1.0.0/authix_python_sdk.egg-info/top_level.txt +1 -0
- authix_python_sdk-1.0.0/requirements.txt +5 -0
- authix_python_sdk-1.0.0/setup.cfg +4 -0
- authix_python_sdk-1.0.0/setup.py +77 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 SecureAuth
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
include requirements.txt
|
|
4
|
+
include MANIFEST.in
|
|
5
|
+
recursive-include secureauth *.py
|
|
6
|
+
recursive-include secureauth *.md
|
|
7
|
+
recursive-include secureauth *.txt
|
|
8
|
+
global-exclude *.pyc
|
|
9
|
+
global-exclude __pycache__
|
|
10
|
+
global-exclude .DS_Store
|
|
11
|
+
global-exclude *.so
|
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: authix-python-sdk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for the Authix authentication service
|
|
5
|
+
Home-page: https://getauthix.online
|
|
6
|
+
Author: Authix Team
|
|
7
|
+
Author-email: support@authix.com
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/authix/python-sdk/issues
|
|
9
|
+
Project-URL: Documentation, https://docs.getauthix.online
|
|
10
|
+
Project-URL: Source Code, https://github.com/authix/python-sdk
|
|
11
|
+
Keywords: authentication security jwt api secureauth login oauth
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Topic :: Internet
|
|
25
|
+
Classifier: Topic :: Security :: Cryptography
|
|
26
|
+
Classifier: Topic :: System :: Systems Administration :: Authentication/Directory
|
|
27
|
+
Requires-Python: >=3.7
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: requests>=2.28.0
|
|
31
|
+
Requires-Dist: cryptography>=3.4.0
|
|
32
|
+
Requires-Dist: flask>=2.0.0
|
|
33
|
+
Requires-Dist: python-dotenv>=0.19.0
|
|
34
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=2.0; extra == "dev"
|
|
38
|
+
Requires-Dist: black>=21.0; extra == "dev"
|
|
39
|
+
Requires-Dist: flake8>=3.8; extra == "dev"
|
|
40
|
+
Requires-Dist: mypy>=0.800; extra == "dev"
|
|
41
|
+
Provides-Extra: docs
|
|
42
|
+
Requires-Dist: sphinx>=4.0; extra == "docs"
|
|
43
|
+
Requires-Dist: sphinx-rtd-theme>=0.5; extra == "docs"
|
|
44
|
+
Dynamic: author
|
|
45
|
+
Dynamic: author-email
|
|
46
|
+
Dynamic: classifier
|
|
47
|
+
Dynamic: description
|
|
48
|
+
Dynamic: description-content-type
|
|
49
|
+
Dynamic: home-page
|
|
50
|
+
Dynamic: keywords
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
Dynamic: project-url
|
|
53
|
+
Dynamic: provides-extra
|
|
54
|
+
Dynamic: requires-dist
|
|
55
|
+
Dynamic: requires-python
|
|
56
|
+
Dynamic: summary
|
|
57
|
+
|
|
58
|
+
# Authix Python SDK
|
|
59
|
+
|
|
60
|
+
[](https://badge.fury.io/py/authix)
|
|
61
|
+
[](https://pypi.org/project/authix/)
|
|
62
|
+
[](https://pypi.org/project/authix/)
|
|
63
|
+
[](https://pypi.org/project/authix/)
|
|
64
|
+
|
|
65
|
+
Official Python SDK for the Authix authentication service.
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install authix
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Quick Start
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
import asyncio
|
|
77
|
+
from authix import AuthixAPI
|
|
78
|
+
|
|
79
|
+
async def main():
|
|
80
|
+
# Initialize with your API key
|
|
81
|
+
api = AuthixAPI(api_key="your_api_key_here")
|
|
82
|
+
|
|
83
|
+
# Register a new user
|
|
84
|
+
result = await api.auth.register(
|
|
85
|
+
username="testuser",
|
|
86
|
+
password="SecurePass123!",
|
|
87
|
+
license_key="AX-XXXX-XXXX-XXXX",
|
|
88
|
+
hwid="device_hash_here",
|
|
89
|
+
app_id="your_app_id",
|
|
90
|
+
app_name="Your App Name"
|
|
91
|
+
)
|
|
92
|
+
print("Registration result:", result)
|
|
93
|
+
|
|
94
|
+
# Login user
|
|
95
|
+
login_result = await api.auth.login(
|
|
96
|
+
username="testuser",
|
|
97
|
+
password="SecurePass123!",
|
|
98
|
+
hwid="device_hash_here",
|
|
99
|
+
app_id="your_app_id",
|
|
100
|
+
app_name="Your App Name"
|
|
101
|
+
)
|
|
102
|
+
print("Login result:", login_result)
|
|
103
|
+
|
|
104
|
+
asyncio.run(main())
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## API Handlers
|
|
108
|
+
|
|
109
|
+
### Authentication
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
# Register user
|
|
113
|
+
await api.auth.register(username, password, license_key, hwid, app_id, app_name)
|
|
114
|
+
|
|
115
|
+
# Login user
|
|
116
|
+
await api.auth.login(username, password, hwid, app_id, app_name)
|
|
117
|
+
|
|
118
|
+
# Logout user
|
|
119
|
+
await api.auth.logout(token)
|
|
120
|
+
|
|
121
|
+
# Refresh token
|
|
122
|
+
await api.auth.refresh_token(refresh_token)
|
|
123
|
+
|
|
124
|
+
# Verify token
|
|
125
|
+
await api.auth.verify_token(token)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Applications
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# List all apps
|
|
132
|
+
apps = await api.apps.get_apps()
|
|
133
|
+
|
|
134
|
+
# Create new app
|
|
135
|
+
app = await api.apps.create_app("My App", description="My description")
|
|
136
|
+
|
|
137
|
+
# Get app details
|
|
138
|
+
details = await api.apps.get_app_details(app_id)
|
|
139
|
+
|
|
140
|
+
# Reset HWID
|
|
141
|
+
await api.apps.reset_hwid(app_id, username, password, license_key)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Licenses
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# Create license
|
|
148
|
+
license = await api.licenses.create_license(app_id, days=30, max_hwids=3)
|
|
149
|
+
|
|
150
|
+
# Get licenses
|
|
151
|
+
licenses = await api.licenses.get_licenses(app_id)
|
|
152
|
+
|
|
153
|
+
# Get license details
|
|
154
|
+
details = await api.licenses.get_license_details(license_key)
|
|
155
|
+
|
|
156
|
+
# Delete unused licenses
|
|
157
|
+
await api.licenses.delete_unused(app_id)
|
|
158
|
+
|
|
159
|
+
# Revoke license
|
|
160
|
+
await api.licenses.revoke_license(license_key)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Users
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
# Get users
|
|
167
|
+
users = await api.users.get_users(app_id)
|
|
168
|
+
|
|
169
|
+
# Get user details
|
|
170
|
+
details = await api.users.get_user_details(app_id, username)
|
|
171
|
+
|
|
172
|
+
# Disable user
|
|
173
|
+
await api.users.disable_user(app_id, username)
|
|
174
|
+
|
|
175
|
+
# Enable user
|
|
176
|
+
await api.users.enable_user(app_id, username)
|
|
177
|
+
|
|
178
|
+
# Delete user
|
|
179
|
+
await api.users.delete_user(app_id, username)
|
|
180
|
+
|
|
181
|
+
# Update user password
|
|
182
|
+
await api.users.update_user_password(app_id, username, new_password)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Security
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# Ban HWID
|
|
189
|
+
await api.security.ban_hwid(app_id, hwid)
|
|
190
|
+
|
|
191
|
+
# Unban HWID
|
|
192
|
+
await api.security.unban_hwid(app_id, hwid)
|
|
193
|
+
|
|
194
|
+
# Ban IP
|
|
195
|
+
await api.security.ban_ip(app_id, ip_address)
|
|
196
|
+
|
|
197
|
+
# Unban IP
|
|
198
|
+
await api.security.unban_ip(app_id, ip_address)
|
|
199
|
+
|
|
200
|
+
# Get banned HWIDs
|
|
201
|
+
banned_hwids = await api.security.get_banned_hwids(app_id)
|
|
202
|
+
|
|
203
|
+
# Get banned IPs
|
|
204
|
+
banned_ips = await api.security.get_banned_ips(app_id)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Webhooks
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
# Create webhook
|
|
211
|
+
webhook = await api.webhooks.create_webhook(
|
|
212
|
+
app_id,
|
|
213
|
+
"https://your-webhook-url.com",
|
|
214
|
+
events=["user.login", "user.register"],
|
|
215
|
+
secret="webhook_secret"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# List webhooks
|
|
219
|
+
webhooks = await api.webhooks.list_webhooks(app_id)
|
|
220
|
+
|
|
221
|
+
# Get webhook details
|
|
222
|
+
details = await api.webhooks.get_webhook_details(app_id, webhook_id)
|
|
223
|
+
|
|
224
|
+
# Update webhook
|
|
225
|
+
await api.webhooks.update_webhook(app_id, webhook_id, url="new_url", events=["user.login"])
|
|
226
|
+
|
|
227
|
+
# Delete webhook
|
|
228
|
+
await api.webhooks.delete_webhook(app_id, webhook_id)
|
|
229
|
+
|
|
230
|
+
# Test webhook
|
|
231
|
+
await api.webhooks.test_webhook(app_id, webhook_id)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Configuration
|
|
235
|
+
|
|
236
|
+
You can configure the SDK in multiple ways:
|
|
237
|
+
|
|
238
|
+
### Method 1: Direct parameters
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
api = AuthixAPI(
|
|
242
|
+
server_url="https://getauthix.online",
|
|
243
|
+
api_key="your_api_key"
|
|
244
|
+
)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Method 2: Environment variables
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
import os
|
|
251
|
+
os.environ["AUTHIX_SERVER"] = "https://getauthix.online"
|
|
252
|
+
os.environ["AUTHIX_API_KEY"] = "your_api_key"
|
|
253
|
+
|
|
254
|
+
api = AuthixAPI() # Will use environment variables
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Error Handling
|
|
258
|
+
|
|
259
|
+
The SDK raises `RuntimeError` for API errors:
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
try:
|
|
263
|
+
await api.auth.login("user", "pass", "hwid", "app_id", "app_name")
|
|
264
|
+
except RuntimeError as e:
|
|
265
|
+
print(f"Authentication failed: {e}")
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Advanced Usage
|
|
269
|
+
|
|
270
|
+
### Using Custom Client
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
from authix import APIClient, AuthHandler
|
|
274
|
+
|
|
275
|
+
client = APIClient(server_url="https://getauthix.online", api_key="your_key")
|
|
276
|
+
auth = AuthHandler(client)
|
|
277
|
+
result = await auth.register(...)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Individual Handlers
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from authix import AppsHandler, APIClient
|
|
284
|
+
|
|
285
|
+
client = APIClient(api_key="your_key")
|
|
286
|
+
apps = AppsHandler(client)
|
|
287
|
+
app_list = await apps.get_apps()
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## CLI Tools
|
|
291
|
+
|
|
292
|
+
The SDK includes a command-line interface:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Set environment variables
|
|
296
|
+
export AUTHIX_API_KEY="your_api_key"
|
|
297
|
+
export AUTHIX_SERVER="https://getauthix.online"
|
|
298
|
+
|
|
299
|
+
# Check server health
|
|
300
|
+
authix-cli health
|
|
301
|
+
|
|
302
|
+
# Register user
|
|
303
|
+
authix-cli register username password license_key hwid app_id app_name
|
|
304
|
+
|
|
305
|
+
# Login user
|
|
306
|
+
authix-cli login username password hwid app_id app_name
|
|
307
|
+
|
|
308
|
+
# List applications
|
|
309
|
+
authix-cli apps
|
|
310
|
+
|
|
311
|
+
# Create application
|
|
312
|
+
authix-cli create-app "My App" --description "My description"
|
|
313
|
+
|
|
314
|
+
# Create license
|
|
315
|
+
authix-cli create-license app_id --days 30 --max-hwids 3
|
|
316
|
+
|
|
317
|
+
# Ban HWID
|
|
318
|
+
authix-cli ban-hwid app_id hwid
|
|
319
|
+
|
|
320
|
+
# Create webhook
|
|
321
|
+
authix-cli create-webhook app_id https://webhook.com --events user.login user.register --secret secret
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
This project is licensed under the GNU General Public License - see the [LICENSE](LICENSE) file for details.
|
|
327
|
+
|
|
328
|
+
## Support
|
|
329
|
+
|
|
330
|
+
- 📖 **Documentation:** [https://docs.getauthix.online](https://docs.getauthix.online)
|
|
331
|
+
- 🐛 **Issues:** [GitHub Issues](https://github.com/authix/python-sdk/issues)
|
|
332
|
+
- 💬 **Discord:** [Join our Discord](https://discord.gg/authix)
|
|
333
|
+
- 📧 **Email:** [support@authix.com](mailto:support@authix.com)
|
|
334
|
+
## Examples
|
|
335
|
+
|
|
336
|
+
### Complete Flask Application
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
from flask import Flask, request, jsonify, render_template_string
|
|
340
|
+
from secureauth_client import SecureAuthClient, SecureAuthFlask, SecureAuthError
|
|
341
|
+
|
|
342
|
+
app = Flask(__name__)
|
|
343
|
+
app.secret_key = 'your-secret-key'
|
|
344
|
+
|
|
345
|
+
# SecureAuth configuration
|
|
346
|
+
app.config['SECUREAUTH_API_KEY'] = 'sak_6266b5a44517a29999cead848062739b81e6d7343f71062eed3001d18b651efa'
|
|
347
|
+
app.config['SECUREAUTH_API_SECRET'] = '40d4435182c2fe81a3ce66b47d9a0d50b6847114d78694c08c7309279fdf231df727d4aa38948f5408524e3a6d5fcb2ff81d40283a3fe1861fabaad6a6eaa867'
|
|
348
|
+
app.config['SECUREAUTH_BASE_URL'] = 'http://localhost:3002'
|
|
349
|
+
|
|
350
|
+
# Initialize SecureAuth
|
|
351
|
+
secureauth = SecureAuthFlask(app)
|
|
352
|
+
|
|
353
|
+
# HTML Template
|
|
354
|
+
HTML_TEMPLATE = """
|
|
355
|
+
<!DOCTYPE html>
|
|
356
|
+
<html>
|
|
357
|
+
<head>
|
|
358
|
+
<title>SecureAuth Python Demo</title>
|
|
359
|
+
<style>
|
|
360
|
+
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
361
|
+
.container { max-width: 600px; margin: 0 auto; }
|
|
362
|
+
.form-group { margin: 15px 0; }
|
|
363
|
+
label { display: block; margin-bottom: 5px; }
|
|
364
|
+
input { width: 100%; padding: 8px; }
|
|
365
|
+
button { padding: 10px 20px; background: #007bff; color: white; border: none; }
|
|
366
|
+
.error { color: red; }
|
|
367
|
+
.success { color: green; }
|
|
368
|
+
</style>
|
|
369
|
+
</head>
|
|
370
|
+
<body>
|
|
371
|
+
<div class="container">
|
|
372
|
+
<h1>SecureAuth Python Demo</h1>
|
|
373
|
+
{% if error %}
|
|
374
|
+
<div class="error">{{ error }}</div>
|
|
375
|
+
{% endif %}
|
|
376
|
+
{% if success %}
|
|
377
|
+
<div class="success">{{ success }}</div>
|
|
378
|
+
{% endif %}
|
|
379
|
+
|
|
380
|
+
{% if not current_user %}
|
|
381
|
+
<form method="post">
|
|
382
|
+
<div class="form-group">
|
|
383
|
+
<label>Email:</label>
|
|
384
|
+
<input type="email" name="email" value="fwaaryn@gmail.com" required>
|
|
385
|
+
</div>
|
|
386
|
+
<div class="form-group">
|
|
387
|
+
<label>Password:</label>
|
|
388
|
+
<input type="password" name="password" value="2117" required>
|
|
389
|
+
</div>
|
|
390
|
+
<button type="submit">Login</button>
|
|
391
|
+
</form>
|
|
392
|
+
{% else %}
|
|
393
|
+
<h2>Welcome, {{ current_user.username }}!</h2>
|
|
394
|
+
<p>Email: {{ current_user.email }}</p>
|
|
395
|
+
<p>Role: {{ current_user.role }}</p>
|
|
396
|
+
<p>Verified: {{ 'Yes' if current_user.is_verified else 'No' }}</p>
|
|
397
|
+
|
|
398
|
+
<h3>API Test Results:</h3>
|
|
399
|
+
<pre>{{ api_results }}</pre>
|
|
400
|
+
|
|
401
|
+
<form method="post" action="/logout">
|
|
402
|
+
<button type="submit">Logout</button>
|
|
403
|
+
</form>
|
|
404
|
+
{% endif %}
|
|
405
|
+
</div>
|
|
406
|
+
</body>
|
|
407
|
+
</html>
|
|
408
|
+
"""
|
|
409
|
+
|
|
410
|
+
@app.route('/')
|
|
411
|
+
def index():
|
|
412
|
+
return render_template_string(HTML_TEMPLATE)
|
|
413
|
+
|
|
414
|
+
@app.route('/', methods=['POST'])
|
|
415
|
+
def login():
|
|
416
|
+
email = request.form.get('email')
|
|
417
|
+
password = request.form.get('password')
|
|
418
|
+
|
|
419
|
+
try:
|
|
420
|
+
# Direct login to SecureAuth server
|
|
421
|
+
import requests
|
|
422
|
+
login_url = f"{app.config['SECUREAUTH_BASE_URL']}/api/v1/auth/login"
|
|
423
|
+
|
|
424
|
+
response = requests.post(login_url, json={
|
|
425
|
+
'email': email,
|
|
426
|
+
'password': password,
|
|
427
|
+
'deviceFingerprint': request.headers.get('User-Agent', '')
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
if response.status_code == 200:
|
|
431
|
+
result = response.json()
|
|
432
|
+
# Store token in session
|
|
433
|
+
from flask import session
|
|
434
|
+
session['access_token'] = result['accessToken']
|
|
435
|
+
session['user'] = result['user']
|
|
436
|
+
|
|
437
|
+
return render_template_string(HTML_TEMPLATE,
|
|
438
|
+
current_user=result['user'],
|
|
439
|
+
success="Login successful!")
|
|
440
|
+
else:
|
|
441
|
+
error_data = response.json() if response.headers.get('content-type') == 'application/json' else {}
|
|
442
|
+
return render_template_string(HTML_TEMPLATE,
|
|
443
|
+
error=error_data.get('error', 'Login failed'))
|
|
444
|
+
|
|
445
|
+
except Exception as e:
|
|
446
|
+
return render_template_string(HTML_TEMPLATE, error=f"Login error: {str(e)}")
|
|
447
|
+
|
|
448
|
+
@app.route('/dashboard')
|
|
449
|
+
@secureauth.require_auth
|
|
450
|
+
def dashboard():
|
|
451
|
+
client = SecureAuthClient(
|
|
452
|
+
app.config['SECUREAUTH_API_KEY'],
|
|
453
|
+
app.config['SECUREAUTH_API_SECRET'],
|
|
454
|
+
app.config['SECUREAUTH_BASE_URL']
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
api_results = {}
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
# Test various API endpoints
|
|
461
|
+
api_results['profile'] = client.get_user_info(request.current_user['id'])
|
|
462
|
+
api_results['sessions'] = client.get_user_sessions(request.current_user['id'])
|
|
463
|
+
|
|
464
|
+
if request.current_user['role'] == 'admin':
|
|
465
|
+
api_results['admin_dashboard'] = client.log_security_event(
|
|
466
|
+
'dashboard_access',
|
|
467
|
+
'low',
|
|
468
|
+
{'user': request.current_user['username']}
|
|
469
|
+
)
|
|
470
|
+
except Exception as e:
|
|
471
|
+
api_results['error'] = str(e)
|
|
472
|
+
|
|
473
|
+
return render_template_string(HTML_TEMPLATE,
|
|
474
|
+
current_user=request.current_user,
|
|
475
|
+
api_results=str(api_results))
|
|
476
|
+
|
|
477
|
+
@app.route('/logout', methods=['POST'])
|
|
478
|
+
def logout():
|
|
479
|
+
from flask import session
|
|
480
|
+
session.clear()
|
|
481
|
+
return render_template_string(HTML_TEMPLATE, success="Logged out successfully!")
|
|
482
|
+
|
|
483
|
+
if __name__ == '__main__':
|
|
484
|
+
app.run(debug=True, host='0.0.0.0', port=5000)
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### FastAPI Integration
|
|
488
|
+
|
|
489
|
+
```python
|
|
490
|
+
from fastapi import FastAPI, Depends, HTTPException, Request
|
|
491
|
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
492
|
+
from secureauth_client import SecureAuthClient, SecureAuthError
|
|
493
|
+
from pydantic import BaseModel
|
|
494
|
+
|
|
495
|
+
app = FastAPI()
|
|
496
|
+
security = HTTPBearer()
|
|
497
|
+
|
|
498
|
+
# Initialize SecureAuth client
|
|
499
|
+
secureauth_client = SecureAuthClient(
|
|
500
|
+
api_key="your_api_key",
|
|
501
|
+
api_secret="your_api_secret",
|
|
502
|
+
base_url="http://localhost:3002"
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
class LoginRequest(BaseModel):
|
|
506
|
+
email: str
|
|
507
|
+
password: str
|
|
508
|
+
|
|
509
|
+
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
|
|
510
|
+
try:
|
|
511
|
+
result = secureauth_client.verify_token(credentials.credentials)
|
|
512
|
+
if not result['success']:
|
|
513
|
+
raise HTTPException(status_code=401, detail="Invalid token")
|
|
514
|
+
return result['user']
|
|
515
|
+
except SecureAuthError as e:
|
|
516
|
+
raise HTTPException(status_code=401, detail=str(e))
|
|
517
|
+
|
|
518
|
+
@app.post("/login")
|
|
519
|
+
async def login(request: LoginRequest):
|
|
520
|
+
try:
|
|
521
|
+
import requests
|
|
522
|
+
response = requests.post("http://localhost:3002/api/v1/auth/login", json={
|
|
523
|
+
"email": request.email,
|
|
524
|
+
"password": request.password,
|
|
525
|
+
"deviceFingerprint": "FastAPI Client"
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
if response.status_code == 200:
|
|
529
|
+
return response.json()
|
|
530
|
+
else:
|
|
531
|
+
raise HTTPException(status_code=400, detail="Login failed")
|
|
532
|
+
except Exception as e:
|
|
533
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
534
|
+
|
|
535
|
+
@app.get("/protected")
|
|
536
|
+
async def protected(current_user: dict = Depends(get_current_user)):
|
|
537
|
+
return {"message": "Access granted", "user": current_user}
|
|
538
|
+
|
|
539
|
+
@app.get("/admin")
|
|
540
|
+
async def admin_only(current_user: dict = Depends(get_current_user)):
|
|
541
|
+
if current_user.get('role') != 'admin':
|
|
542
|
+
raise HTTPException(status_code=403, detail="Admin access required")
|
|
543
|
+
return {"message": "Admin access granted", "user": current_user}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
## Configuration
|
|
547
|
+
|
|
548
|
+
### Environment Variables
|
|
549
|
+
|
|
550
|
+
Create a `.env` file in your project:
|
|
551
|
+
|
|
552
|
+
```env
|
|
553
|
+
SECUREAUTH_API_KEY=your_api_key_here
|
|
554
|
+
SECUREAUTH_API_SECRET=your_api_secret_here
|
|
555
|
+
SECUREAUTH_BASE_URL=http://localhost:3002
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### Configuration File
|
|
559
|
+
|
|
560
|
+
```python
|
|
561
|
+
# config.py
|
|
562
|
+
import os
|
|
563
|
+
from dotenv import load_dotenv
|
|
564
|
+
|
|
565
|
+
load_dotenv()
|
|
566
|
+
|
|
567
|
+
SECUREAUTH_CONFIG = {
|
|
568
|
+
'api_key': os.getenv('SECUREAUTH_API_KEY'),
|
|
569
|
+
'api_secret': os.getenv('SECUREAUTH_API_SECRET'),
|
|
570
|
+
'base_url': os.getenv('SECUREAUTH_BASE_URL', 'http://localhost:3002'),
|
|
571
|
+
'timeout': 30,
|
|
572
|
+
'retry_attempts': 3
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
## Error Handling
|
|
577
|
+
|
|
578
|
+
```python
|
|
579
|
+
from secureauth_client import SecureAuthError, SecureAuthClient
|
|
580
|
+
|
|
581
|
+
try:
|
|
582
|
+
client = SecureAuthClient(api_key, api_secret, base_url)
|
|
583
|
+
result = client.verify_token(token)
|
|
584
|
+
except SecureAuthError as e:
|
|
585
|
+
print(f"SecureAuth error: {e}")
|
|
586
|
+
# Handle authentication error
|
|
587
|
+
except Exception as e:
|
|
588
|
+
print(f"Unexpected error: {e}")
|
|
589
|
+
# Handle other errors
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
## Security Best Practices
|
|
593
|
+
|
|
594
|
+
1. **Store credentials securely**: Use environment variables, not hardcoded values
|
|
595
|
+
2. **Use HTTPS**: Always use HTTPS in production
|
|
596
|
+
3. **Validate tokens**: Always verify tokens on each request
|
|
597
|
+
4. **Handle errors gracefully**: Don't expose sensitive information in error messages
|
|
598
|
+
5. **Implement rate limiting**: Add client-side rate limiting
|
|
599
|
+
6. **Log security events**: Log authentication attempts and failures
|
|
600
|
+
|
|
601
|
+
## Testing
|
|
602
|
+
|
|
603
|
+
```python
|
|
604
|
+
import unittest
|
|
605
|
+
from secureauth_client import SecureAuthClient, SecureAuthError
|
|
606
|
+
|
|
607
|
+
class TestSecureAuthClient(unittest.TestCase):
|
|
608
|
+
def setUp(self):
|
|
609
|
+
self.client = SecureAuthClient(
|
|
610
|
+
api_key="test_key",
|
|
611
|
+
api_secret="test_secret",
|
|
612
|
+
base_url="http://localhost:3002"
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
def test_verify_token(self):
|
|
616
|
+
# Test with valid token
|
|
617
|
+
result = self.client.verify_token("valid_token")
|
|
618
|
+
self.assertTrue(result['success'])
|
|
619
|
+
|
|
620
|
+
def test_verify_invalid_token(self):
|
|
621
|
+
# Test with invalid token
|
|
622
|
+
with self.assertRaises(SecureAuthError):
|
|
623
|
+
self.client.verify_token("invalid_token")
|
|
624
|
+
|
|
625
|
+
if __name__ == '__main__':
|
|
626
|
+
unittest.main()
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
## Deployment
|
|
630
|
+
|
|
631
|
+
### Docker
|
|
632
|
+
|
|
633
|
+
```dockerfile
|
|
634
|
+
FROM python:3.9-slim
|
|
635
|
+
|
|
636
|
+
WORKDIR /app
|
|
637
|
+
|
|
638
|
+
COPY requirements.txt .
|
|
639
|
+
RUN pip install -r requirements.txt
|
|
640
|
+
|
|
641
|
+
COPY secureauth_client.py .
|
|
642
|
+
COPY your_app.py .
|
|
643
|
+
|
|
644
|
+
EXPOSE 5000
|
|
645
|
+
|
|
646
|
+
CMD ["python", "your_app.py"]
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Requirements.txt
|
|
650
|
+
|
|
651
|
+
```
|
|
652
|
+
requests>=2.28.0
|
|
653
|
+
cryptography>=3.4.0
|
|
654
|
+
flask>=2.0.0 # if using Flask
|
|
655
|
+
django>=4.0.0 # if using Django
|
|
656
|
+
fastapi>=0.68.0 # if using FastAPI
|
|
657
|
+
python-dotenv>=0.19.0
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
## Support
|
|
661
|
+
|
|
662
|
+
For issues and questions:
|
|
663
|
+
1. Check the [SecureAuth Documentation](../INTEGRATION_GUIDE.md)
|
|
664
|
+
2. Review the API endpoints in your SecureAuth server
|
|
665
|
+
3. Test with the provided examples
|
|
666
|
+
4. Check server logs for authentication errors
|