d43eb54e2d59cfbf61da0bdb2dd91c7cc32c6631
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. The demo UI is available at http://localhost:8080. 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.debug: local-only provider that stores the latest OTP in Redis for the demo UI.
Demo UI
demo-app is a small FastAPI backend-for-frontend that calls auth-service over gRPC. It demonstrates how another microservice consumes the auth service.
Available browser actions:
- Request and verify OTP.
- Fetch the local debug OTP when
DEMO_ENABLE_DEBUG_OTP=true. - Call public, authenticated-user, and admin-only gRPC methods.
- Refresh and revoke tokens.
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.
Description
Languages
Python
91.8%
JavaScript
3.3%
CSS
2%
HTML
2%
Dockerfile
0.5%
Other
0.4%