Spaces:
Running
Running
Commit
·
dceb0eb
1
Parent(s):
7d369c8
fix: point app.yaml to Ruturaj2506/demo-auth fork
Browse files- .do/app.yaml +79 -0
- .dockerignore +64 -0
- .env.example +40 -0
- Dockerfile +42 -0
- Procfile +1 -0
- adaptiveauth/config.py +11 -6
- adaptiveauth/models/feature_importances.json +19 -0
- adaptiveauth/models/feature_names.json +19 -0
- adaptiveauth/models/learned_weights.json +7 -0
- adaptiveauth/models/model_meta.json +23 -0
- adaptiveauth/models/rba_xgb_model.json +0 -0
- requirements.txt +1 -0
.do/app.yaml
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DigitalOcean App Platform spec
|
| 2 |
+
# Docs: https://docs.digitalocean.com/products/app-platform/reference/app-spec/
|
| 3 |
+
#
|
| 4 |
+
# Repo: https://github.com/Ruturaj2506/demo-auth
|
| 5 |
+
#
|
| 6 |
+
# HOW TO DEPLOY:
|
| 7 |
+
# 1. Go to https://cloud.digitalocean.com/apps → "Create App"
|
| 8 |
+
# 2. Connect GitHub → select Ruturaj2506/demo-auth → branch: main
|
| 9 |
+
# 3. DO auto-detects this file — click "Deploy"
|
| 10 |
+
# 5. App URL printed once build finishes (~3-5 min)
|
| 11 |
+
|
| 12 |
+
name: adaptiveauth
|
| 13 |
+
|
| 14 |
+
# ── Backend (FastAPI) ─────────────────────────────────────────────────────────
|
| 15 |
+
services:
|
| 16 |
+
- name: api
|
| 17 |
+
dockerfile_path: Dockerfile
|
| 18 |
+
source_dir: /
|
| 19 |
+
github:
|
| 20 |
+
repo: Ruturaj2506/demo-auth
|
| 21 |
+
branch: main
|
| 22 |
+
deploy_on_push: true
|
| 23 |
+
http_port: 8000
|
| 24 |
+
instance_count: 1
|
| 25 |
+
instance_size_slug: basic-xxs # cheapest tier (~$5/mo, free with student credits)
|
| 26 |
+
health_check:
|
| 27 |
+
http_path: /health
|
| 28 |
+
initial_delay_seconds: 15
|
| 29 |
+
period_seconds: 30
|
| 30 |
+
envs:
|
| 31 |
+
# Injected automatically by DO when you add a managed DB below
|
| 32 |
+
- key: DATABASE_URL
|
| 33 |
+
scope: RUN_TIME
|
| 34 |
+
value: ${adaptiveauth-db.DATABASE_URL}
|
| 35 |
+
|
| 36 |
+
# CHANGE THIS — generate a strong key: python -c "import secrets; print(secrets.token_hex(32))"
|
| 37 |
+
- key: SECRET_KEY
|
| 38 |
+
scope: RUN_TIME
|
| 39 |
+
type: SECRET
|
| 40 |
+
value: "REPLACE_WITH_YOUR_STRONG_SECRET_KEY"
|
| 41 |
+
|
| 42 |
+
- key: ADAPTIVEAUTH_RISK_DEVICE_WEIGHT
|
| 43 |
+
scope: RUN_TIME
|
| 44 |
+
value: "0.21"
|
| 45 |
+
- key: ADAPTIVEAUTH_RISK_LOCATION_WEIGHT
|
| 46 |
+
scope: RUN_TIME
|
| 47 |
+
value: "97.68"
|
| 48 |
+
- key: ADAPTIVEAUTH_RISK_TIME_WEIGHT
|
| 49 |
+
scope: RUN_TIME
|
| 50 |
+
value: "0.02"
|
| 51 |
+
- key: ADAPTIVEAUTH_RISK_VELOCITY_WEIGHT
|
| 52 |
+
scope: RUN_TIME
|
| 53 |
+
value: "2.08"
|
| 54 |
+
- key: ADAPTIVEAUTH_RISK_BEHAVIOR_WEIGHT
|
| 55 |
+
scope: RUN_TIME
|
| 56 |
+
value: "0.01"
|
| 57 |
+
|
| 58 |
+
# Optional — fill in if you want email alerts / OTP via email
|
| 59 |
+
- key: ADAPTIVEAUTH_MAIL_USERNAME
|
| 60 |
+
scope: RUN_TIME
|
| 61 |
+
value: ""
|
| 62 |
+
- key: ADAPTIVEAUTH_MAIL_PASSWORD
|
| 63 |
+
scope: RUN_TIME
|
| 64 |
+
type: SECRET
|
| 65 |
+
value: ""
|
| 66 |
+
- key: ADAPTIVEAUTH_MAIL_FROM
|
| 67 |
+
scope: RUN_TIME
|
| 68 |
+
value: ""
|
| 69 |
+
- key: ADAPTIVEAUTH_MAIL_SERVER
|
| 70 |
+
scope: RUN_TIME
|
| 71 |
+
value: ""
|
| 72 |
+
|
| 73 |
+
# ── Managed PostgreSQL Database ───────────────────────────────────────────────
|
| 74 |
+
databases:
|
| 75 |
+
- name: adaptiveauth-db
|
| 76 |
+
engine: PG # PostgreSQL 16
|
| 77 |
+
version: "16"
|
| 78 |
+
size: db-s-dev-database # smallest/free-eligible dev database
|
| 79 |
+
num_nodes: 1
|
.dockerignore
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*.pyo
|
| 5 |
+
*.pyd
|
| 6 |
+
*.egg
|
| 7 |
+
*.egg-info/
|
| 8 |
+
dist/
|
| 9 |
+
build/
|
| 10 |
+
.eggs/
|
| 11 |
+
*.whl
|
| 12 |
+
|
| 13 |
+
# Virtual environments
|
| 14 |
+
.venv/
|
| 15 |
+
venv/
|
| 16 |
+
env/
|
| 17 |
+
ENV/
|
| 18 |
+
|
| 19 |
+
# Environment secrets — never bake these into the image
|
| 20 |
+
.env
|
| 21 |
+
*.env
|
| 22 |
+
|
| 23 |
+
# Database files — use managed PostgreSQL in production
|
| 24 |
+
*.db
|
| 25 |
+
*.sqlite
|
| 26 |
+
*.sqlite3
|
| 27 |
+
|
| 28 |
+
# Tests and dev tools
|
| 29 |
+
test_*.py
|
| 30 |
+
*_test.py
|
| 31 |
+
pytest.ini
|
| 32 |
+
.pytest_cache/
|
| 33 |
+
.coverage
|
| 34 |
+
htmlcov/
|
| 35 |
+
.mypy_cache/
|
| 36 |
+
.ruff_cache/
|
| 37 |
+
|
| 38 |
+
# IDE
|
| 39 |
+
.vscode/
|
| 40 |
+
.idea/
|
| 41 |
+
*.code-workspace
|
| 42 |
+
|
| 43 |
+
# OS
|
| 44 |
+
.DS_Store
|
| 45 |
+
Thumbs.db
|
| 46 |
+
|
| 47 |
+
# Git
|
| 48 |
+
.git/
|
| 49 |
+
.gitignore
|
| 50 |
+
|
| 51 |
+
# Docs (not needed at runtime)
|
| 52 |
+
README.md
|
| 53 |
+
HOW_TO_TEST.md
|
| 54 |
+
LICENSE
|
| 55 |
+
*.md
|
| 56 |
+
|
| 57 |
+
# Temp / JSON test files
|
| 58 |
+
openapi_temp.json
|
| 59 |
+
openapi_test.json
|
| 60 |
+
run_example.py
|
| 61 |
+
start_server.*
|
| 62 |
+
|
| 63 |
+
# Model source (already copied into image)
|
| 64 |
+
# (included intentionally — XGBoost weights are needed at runtime)
|
.env.example
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ──────────────────────────────────────────────────────────────────────────────
|
| 2 |
+
# AdaptiveAuth — Environment Variables
|
| 3 |
+
# Copy this file to .env and fill in your values (never commit .env to git!)
|
| 4 |
+
# ──────────────────────────────────────────────────────────────────────────────
|
| 5 |
+
|
| 6 |
+
# ── Database ──────────────────────────────────────────────────────────────────
|
| 7 |
+
# For local dev, SQLite is fine:
|
| 8 |
+
DATABASE_URL=sqlite:///./adaptiveauth.db
|
| 9 |
+
# For production (DigitalOcean Managed Postgres — value injected automatically by App Platform):
|
| 10 |
+
# DATABASE_URL=postgresql://user:password@host:port/dbname
|
| 11 |
+
|
| 12 |
+
# ── Security ──────────────────────────────────────────────────────────────────
|
| 13 |
+
# Generate with: python -c "import secrets; print(secrets.token_hex(32))"
|
| 14 |
+
SECRET_KEY=REPLACE_WITH_A_STRONG_RANDOM_SECRET_KEY_AT_LEAST_32_CHARS
|
| 15 |
+
ADAPTIVEAUTH_ALGORITHM=HS256
|
| 16 |
+
ADAPTIVEAUTH_ACCESS_TOKEN_EXPIRE_MINUTES=30
|
| 17 |
+
ADAPTIVEAUTH_REFRESH_TOKEN_EXPIRE_DAYS=7
|
| 18 |
+
|
| 19 |
+
# ── Risk Weights (AI-learned from XGBoost model) ──────────────────────────────
|
| 20 |
+
ADAPTIVEAUTH_RISK_DEVICE_WEIGHT=0.21
|
| 21 |
+
ADAPTIVEAUTH_RISK_LOCATION_WEIGHT=97.68
|
| 22 |
+
ADAPTIVEAUTH_RISK_TIME_WEIGHT=0.02
|
| 23 |
+
ADAPTIVEAUTH_RISK_VELOCITY_WEIGHT=2.08
|
| 24 |
+
ADAPTIVEAUTH_RISK_BEHAVIOR_WEIGHT=0.01
|
| 25 |
+
|
| 26 |
+
# ── Risk Thresholds ───────────────────────────────────────────────────────────
|
| 27 |
+
ADAPTIVEAUTH_RISK_LOW_THRESHOLD=25.0
|
| 28 |
+
ADAPTIVEAUTH_RISK_MEDIUM_THRESHOLD=50.0
|
| 29 |
+
ADAPTIVEAUTH_RISK_HIGH_THRESHOLD=75.0
|
| 30 |
+
|
| 31 |
+
# ── Email (optional — needed for OTP/alerts) ──────────────────────────────────
|
| 32 |
+
ADAPTIVEAUTH_MAIL_USERNAME=your@email.com
|
| 33 |
+
ADAPTIVEAUTH_MAIL_PASSWORD=your_app_password
|
| 34 |
+
ADAPTIVEAUTH_MAIL_FROM=your@email.com
|
| 35 |
+
ADAPTIVEAUTH_MAIL_SERVER=smtp.gmail.com
|
| 36 |
+
ADAPTIVEAUTH_MAIL_PORT=587
|
| 37 |
+
|
| 38 |
+
# ── CORS ─────────────────────────────────────────────────────────────────────
|
| 39 |
+
# Replace * with your frontend domain in production
|
| 40 |
+
# ADAPTIVEAUTH_CORS_ORIGINS=["https://your-app.ondigitalocean.app"]
|
Dockerfile
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ── Stage 1: build dependencies ──────────────────────────────────────────────
|
| 2 |
+
FROM python:3.11-slim AS builder
|
| 3 |
+
|
| 4 |
+
WORKDIR /app
|
| 5 |
+
|
| 6 |
+
# Install build tools needed for some wheels (psycopg2, cryptography, etc.)
|
| 7 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 8 |
+
build-essential \
|
| 9 |
+
libpq-dev \
|
| 10 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 11 |
+
|
| 12 |
+
COPY requirements.txt .
|
| 13 |
+
RUN pip install --no-cache-dir --user -r requirements.txt
|
| 14 |
+
|
| 15 |
+
# ── Stage 2: slim runtime image ───────────────────────────────────────────────
|
| 16 |
+
FROM python:3.11-slim
|
| 17 |
+
|
| 18 |
+
# Runtime lib for psycopg2
|
| 19 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 20 |
+
libpq5 \
|
| 21 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 22 |
+
|
| 23 |
+
WORKDIR /app
|
| 24 |
+
|
| 25 |
+
# Copy installed packages from builder
|
| 26 |
+
COPY --from=builder /root/.local /root/.local
|
| 27 |
+
|
| 28 |
+
# Copy application source
|
| 29 |
+
COPY . .
|
| 30 |
+
|
| 31 |
+
ENV PATH=/root/.local/bin:$PATH \
|
| 32 |
+
PYTHONDONTWRITEBYTECODE=1 \
|
| 33 |
+
PYTHONUNBUFFERED=1 \
|
| 34 |
+
PORT=8000
|
| 35 |
+
|
| 36 |
+
EXPOSE 8000
|
| 37 |
+
|
| 38 |
+
# Non-root user for security
|
| 39 |
+
RUN adduser --disabled-password --gecos "" appuser && chown -R appuser /app
|
| 40 |
+
USER appuser
|
| 41 |
+
|
| 42 |
+
CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port $PORT --workers 2"]
|
Procfile
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
web: uvicorn main:app --host 0.0.0.0 --port $PORT --workers 2
|
adaptiveauth/config.py
CHANGED
|
@@ -77,13 +77,18 @@ class AdaptiveAuthSettings(BaseSettings):
|
|
| 77 |
|
| 78 |
|
| 79 |
class RiskFactorWeights(BaseSettings):
|
| 80 |
-
"""Configuration for risk factor weights in risk assessment.
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
class Config:
|
| 89 |
env_prefix = "ADAPTIVEAUTH_RISK_"
|
|
|
|
| 77 |
|
| 78 |
|
| 79 |
class RiskFactorWeights(BaseSettings):
|
| 80 |
+
"""Configuration for risk factor weights in risk assessment.
|
| 81 |
|
| 82 |
+
Weights are learned from the trained XGBoost model (rba_xgb_model.json).
|
| 83 |
+
Trained on Kaggle RBA dataset (1.6M rows), ROC-AUC: 1.0.
|
| 84 |
+
Updated: 2026-02-20
|
| 85 |
+
"""
|
| 86 |
+
|
| 87 |
+
DEVICE_WEIGHT: float = Field(default=0.21, description="Weight for device factor (AI-learned)")
|
| 88 |
+
LOCATION_WEIGHT: float = Field(default=97.68, description="Weight for location/IP factor (AI-learned)")
|
| 89 |
+
TIME_WEIGHT: float = Field(default=0.02, description="Weight for time factor (AI-learned)")
|
| 90 |
+
VELOCITY_WEIGHT: float = Field(default=2.08, description="Weight for velocity factor (AI-learned)")
|
| 91 |
+
BEHAVIOR_WEIGHT: float = Field(default=0.01, description="Weight for behavior factor (AI-learned)")
|
| 92 |
|
| 93 |
class Config:
|
| 94 |
env_prefix = "ADAPTIVEAUTH_RISK_"
|
adaptiveauth/models/feature_importances.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"is_attack_ip": 0.967225193977356,
|
| 3 |
+
"ip_failure_count": 0.019231485202908516,
|
| 4 |
+
"country_freq": 0.00756910489872098,
|
| 5 |
+
"asn_risk": 0.0019815003033727407,
|
| 6 |
+
"is_bot": 0.0013159684604033828,
|
| 7 |
+
"ip_attempt_count": 0.0009205246460624039,
|
| 8 |
+
"device_type": 0.0007694000960327685,
|
| 9 |
+
"user_recent_failures": 0.0006265112315304577,
|
| 10 |
+
"login_hour": 9.224589302903041e-05,
|
| 11 |
+
"rtt_zscore": 5.906149817747064e-05,
|
| 12 |
+
"user_success_rate": 5.211737152421847e-05,
|
| 13 |
+
"is_new_country": 5.003463229513727e-05,
|
| 14 |
+
"is_new_browser": 4.279694985598326e-05,
|
| 15 |
+
"login_day": 2.7936024707742035e-05,
|
| 16 |
+
"is_late_night": 2.1642506908392534e-05,
|
| 17 |
+
"is_weekend": 1.440843607269926e-05,
|
| 18 |
+
"is_unknown_device": 0.0
|
| 19 |
+
}
|
adaptiveauth/models/feature_names.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
"device_type",
|
| 3 |
+
"is_bot",
|
| 4 |
+
"is_unknown_device",
|
| 5 |
+
"is_new_browser",
|
| 6 |
+
"is_attack_ip",
|
| 7 |
+
"is_new_country",
|
| 8 |
+
"country_freq",
|
| 9 |
+
"asn_risk",
|
| 10 |
+
"login_hour",
|
| 11 |
+
"login_day",
|
| 12 |
+
"is_late_night",
|
| 13 |
+
"is_weekend",
|
| 14 |
+
"user_recent_failures",
|
| 15 |
+
"ip_attempt_count",
|
| 16 |
+
"ip_failure_count",
|
| 17 |
+
"rtt_zscore",
|
| 18 |
+
"user_success_rate"
|
| 19 |
+
]
|
adaptiveauth/models/learned_weights.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"device": 0.20999999344348907,
|
| 3 |
+
"location": 97.68000030517578,
|
| 4 |
+
"time": 0.019999999552965164,
|
| 5 |
+
"velocity": 2.0799999237060547,
|
| 6 |
+
"behavior": 0.009999999776482582
|
| 7 |
+
}
|
adaptiveauth/models/model_meta.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"trained_at": "2026-02-20T20:25:07.626832",
|
| 3 |
+
"dataset": "kaggle:dasgroup/rba-dataset",
|
| 4 |
+
"rows_train": 1600000,
|
| 5 |
+
"rows_test": 400000,
|
| 6 |
+
"roc_auc": 1.0,
|
| 7 |
+
"n_features": 17,
|
| 8 |
+
"old_weights": {
|
| 9 |
+
"device": 25.0,
|
| 10 |
+
"location": 25.0,
|
| 11 |
+
"time": 15.0,
|
| 12 |
+
"velocity": 20.0,
|
| 13 |
+
"behavior": 15.0
|
| 14 |
+
},
|
| 15 |
+
"weights_applied_at": "2026-02-21T00:00:00.000000",
|
| 16 |
+
"learned_weights": {
|
| 17 |
+
"device": 0.20999999344348907,
|
| 18 |
+
"location": 97.68000030517578,
|
| 19 |
+
"time": 0.019999999552965164,
|
| 20 |
+
"velocity": 2.0799999237060547,
|
| 21 |
+
"behavior": 0.009999999776482582
|
| 22 |
+
}
|
| 23 |
+
}
|
adaptiveauth/models/rba_xgb_model.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
requirements.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
# AdaptiveAuth Framework - Production Dependencies
|
| 2 |
fastapi>=0.104.0
|
|
|
|
| 3 |
uvicorn[standard]>=0.24.0
|
| 4 |
sqlalchemy>=2.0.0
|
| 5 |
pydantic>=2.0.0
|
|
|
|
| 1 |
# AdaptiveAuth Framework - Production Dependencies
|
| 2 |
fastapi>=0.104.0
|
| 3 |
+
psycopg2-binary>=2.9.9
|
| 4 |
uvicorn[standard]>=0.24.0
|
| 5 |
sqlalchemy>=2.0.0
|
| 6 |
pydantic>=2.0.0
|