2.1 KiB
2.1 KiB
Gapido Backend Code Challenge
Python gRPC OTP authentication service with MongoDB, Redis, RabbitMQ, and selectable SMS providers.
Architecture
auth-service: asyncgrpc.aioAPI for OTP login, token refresh, token revocation, and RBAC demo methods.sms-worker: RabbitMQ consumer that sends OTP messages through the configured SMS provider.- MongoDB stores users and refresh-token sessions.
- Redis stores OTP hashes, TTL, verification attempts, and OTP request rate limits.
- RabbitMQ decouples authentication from SMS delivery.
Run
cp .env.example .env
docker compose up --build
The gRPC service listens on localhost:50051. RabbitMQ management is available at http://localhost:15672 with guest / guest.
SMS Provider
The SMS integration uses the Strategy pattern behind the SmsClient port. Select the provider with:
SMS_PROVIDER=kavenegar
Supported values:
kavenegar: usesKAVENEGAR_API_KEYandKAVENEGAR_LOGIN_TEMPLATE.sms_ir: usesSMS_IR_API_KEYandSMS_IR_VERIFY_TEMPLATE_ID.
Local Development
python -m venv .venv
pip install -e ".[dev]"
python -m gapido_auth.tools.generate_proto
pytest
gRPC Methods
RequestOtp: public; creates a short-lived OTP and publishes an SMS job.VerifyOtp: public; verifies OTP and returns access and refresh tokens.RefreshToken: public; rotates refresh token and returns a new token pair.RevokeRefreshToken: authenticated; revokes a refresh token session.PublicPing: public.UserOnly: requires any authenticated active user.AdminOnly: requires an authenticated admin.
Protected calls use metadata:
authorization: Bearer <access_token>
Security Notes
- OTP codes are generated with
secrets, stored only as HMAC hashes in Redis, and expire after 120 seconds by default. - OTP requests are rate-limited per mobile number and client identity.
- Refresh tokens are opaque random values; only SHA-256 hashes are persisted.
- Refresh tokens rotate on use.
- SMS providers are hidden behind adapters and mocked in tests.