Skip to main content

Production-grade auth SDK for Indian apps — Email OTP, PIN, DPDP consent, device trust

Project description

BharatAuth

Production-grade auth SDK for Indian apps.

Email OTP · Password login · PIN app-lock · DPDP consent · Device trust matrix · Brute-force protection

Built from a real production auth system. Battle-tested on FastAPI + PostgreSQL.


Install

pip install bharatauth

Quick Start

Managed mode (new project — no existing user table)

from bharatauth import configure

configure(
    mode="managed",
    secret_key="change-me-in-production",
    database_url="postgresql://user:pass@localhost/mydb",
    smtp_host="smtp.yourprovider.com",
    smtp_user="noreply@yourapp.com",
    smtp_password="...",
)

BharatAuth creates ba_users, ba_accounts, ba_sessions, ba_otp_tokens, ba_consent_log, ba_ip_blocks and manages them entirely.

External mode (you already have a User model)

from bharatauth import configure

configure(
    mode="external",
    secret_key="change-me-in-production",
    database_url="postgresql://user:pass@localhost/mydb",
    get_user_by_email=lambda db, email: db.query(MyUser).filter_by(email=email).first(),
    get_user_by_username=lambda db, u: db.query(MyUser).filter_by(username=u).first(),
    get_user_id=lambda user: str(user.id),
    get_user_email=lambda user: user.email,
    get_user_display_name=lambda user: user.first_name,
)

BharatAuth stores sessions, OTP tokens, and DPDP consent logs in its own ba_* tables using your user's ID as an opaque string. Your user table is never touched.


Drop-in FastAPI Router

from fastapi import FastAPI
from bharatauth.fastapi_router import router as auth_router, bharatauth_exception_handler
from bharatauth.exceptions import BharatAuthError

app = FastAPI()
app.add_exception_handler(BharatAuthError, bharatauth_exception_handler)
app.include_router(auth_router, prefix="/auth", tags=["Auth"])

This mounts:

Method Path Description
POST /auth/login Password login
POST /auth/otp/request Send OTP email
POST /auth/otp/verify Verify OTP, create session
POST /auth/pin/set Set/change PIN
POST /auth/pin/verify Verify PIN (app-lock)
POST /auth/pin/reset/request PIN reset email
POST /auth/pin/reset/confirm Confirm PIN reset
POST /auth/refresh Rotate refresh token
POST /auth/logout Revoke session
POST /auth/logout-all Revoke all sessions
GET /auth/sessions List active sessions
GET /auth/me Current user from token
GET /auth/privacy/consents DPDP consent dashboard
POST /auth/privacy/consent/withdraw Withdraw consent category
GET /auth/privacy/export DPDP Right of Access export

Use Directly (without the router)

from bharatauth.login import login, refresh_session, logout
from bharatauth.otp   import request_otp, verify_otp
from bharatauth.pin   import set_pin, verify_pin
from bharatauth.dpdp  import record_consent, get_consents, withdraw_consent, export_user_data

# Password login
result = login(db, identifier="user@example.com", password="secret",
               device_fingerprint="sha256...", is_public_device=False)

# Email OTP
request_otp(db, identifier="user@example.com", device_fingerprint="sha256...")
verify_otp(db, identifier="user@example.com", otp_code="483920", device_fingerprint="sha256...")

# PIN
set_pin(db, user=user_obj, pin="4829")
verify_pin(db, user=user_obj, pin="4829")

# DPDP — record consent at registration
from bharatauth.dpdp import validate_registration_consent, record_bulk_consent

consents = [
    {"category": "identity", "granted": True},
    {"category": "contact", "granted": True},
    {"category": "location", "granted": True},
    {"category": "security", "granted": True},
    {"category": "communications", "granted": True},
    {"category": "analytics", "granted": True},
]
validate_registration_consent(consents)  # raises ConsentRequiredError if any missing
record_bulk_consent(db, user_id=str(user.id), consents=consents, ip_address="...")

Security Model

Session Trust Matrix

Scenario TTL Step-up Required
Own device, known 30 days None
Own device, OTP login 30 days None
New unrecognised device 7 days Before sensitive actions
Public / borrowed device 2 hours Every sensitive action

Brute-Force Protection (two layers)

Layer 1 — Route-level (Redis): Per-IP request rate limits. Fails open if Redis is unavailable — auth correctness is maintained by Layer 2.

Layer 2 — Service-level (PostgreSQL): Per-account failure counting. Redis-independent.

Tier Trigger Action
Soft lock 5 failures Locked 7 minutes (423)
Hard lock 10 failures Email verification required (423)
IP block 3+ distinct accounts from same IP IP blocked 24h (429)

PIN Security

PIN lockout returns 401, not 423. An attacker with a stolen JWT receives no signal that lockout triggered — 401 is indistinguishable from wrong PIN.


DPDP Compliance (India)

BharatAuth implements the Digital Personal Data Protection Act 2023:

  • Six consent categories: identity, contact, location, security, communications, analytics
  • Immutable audit trail: consent records are never updated or deleted — new rows only
  • Notice versioning: each consent row records the exact privacy notice version shown
  • Right of withdrawal: as easy as granting (single POST, DPDP §6)
  • Right of access: export_user_data() returns all auth data BharatAuth holds
  • Configurable categories: override via BharatAuthConfig.dpdp_categories

Configuration Reference

configure(
    # Required
    mode="managed",               # "managed" | "external"
    secret_key="...",             # JWT signing secret

    # Database (one of these is required)
    database_url="postgresql://...",
    db_session_factory=get_db,    # your own SQLAlchemy session factory

    # Token TTLs
    access_token_expire_minutes=15,
    refresh_token_expire_days=30,
    new_device_token_expire_days=7,
    public_device_token_expire_hours=2,
    otp_expire_minutes=10,

    # Email (SMTP)
    smtp_host="smtp.example.com",
    smtp_port=587,
    smtp_user="noreply@example.com",
    smtp_password="...",
    smtp_from="noreply@example.com",
    smtp_tls=True,

    # Redis (optional — rate limiting only, fails open without it)
    redis_url="redis://localhost:6379",

    # JWT claims
    jwt_issuer="your-app",
    jwt_audience="your-app-client",

    # DPDP
    dpdp_notice_version="1.0.0",
    dpdp_categories=["identity", "contact", "location",
                     "security", "communications", "analytics"],

    # External mode only
    get_user_by_email=...,
    get_user_by_username=...,
    get_user_id=...,
    get_user_email=...,
    get_user_display_name=...,    # optional, for email templates
)

Custom Email Backend

Swap the SMTP backend with any provider (SES, SendGrid, etc.):

from bharatauth.email import set_email_backend

class MyEmailBackend:
    def send(self, *, to, subject, body_text, body_html=None):
        # your implementation
        my_email_client.send(to=to, subject=subject, body=body_text)

set_email_backend(MyEmailBackend())

License

MIT — Copyright JamBuster Technologies Pvt Ltd

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bharatauth-0.1.0.tar.gz (32.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bharatauth-0.1.0-py3-none-any.whl (37.6 kB view details)

Uploaded Python 3

File details

Details for the file bharatauth-0.1.0.tar.gz.

File metadata

  • Download URL: bharatauth-0.1.0.tar.gz
  • Upload date:
  • Size: 32.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for bharatauth-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3ca772475ec35b2fffc4a7df5c6e4db0b4ce52facb13746e1d46ab4305f95d94
MD5 94eecbf3e91b19ede56ebce742910825
BLAKE2b-256 f71d640e306d22b1c72575341df9aea92e05759a2c2207ff32acc214a471274c

See more details on using hashes here.

File details

Details for the file bharatauth-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: bharatauth-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 37.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for bharatauth-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fc69c816268661b43345f5837a581ecf2e60228cb3ffb03bb40a1fec091cb9ea
MD5 a1a68f06293233e22491802de4438eef
BLAKE2b-256 e57d2f9716cef8035ce5eae5b801c0c098b65b0dc632f5f72d89bc05f8d0e931

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page