Gapido Backend Code Challenge

Python gRPC OTP authentication service with MongoDB, Redis, RabbitMQ, and selectable SMS providers.

Architecture

  • auth-service: async grpc.aio API 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 -f docker-compose.yml -f docker-compose.local.yml 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.

Production Deployment

Production uses Caddy as the only public entrypoint for https://gapido.amiirkhl.ir.

cp .env.production.example .env.production
docker compose --env-file .env.production -f docker-compose.yml -f docker-compose.prod.yml up -d --build

Before running production, set real values in .env.production:

  • JWT_SECRET_KEY
  • ADMIN_MOBILE
  • SMS_PROVIDER
  • the selected SMS provider credentials

Only ports 80 and 443 are published in the production Compose overlay. MongoDB, Redis, RabbitMQ, gRPC, and the FastAPI demo service stay private on the Docker network.

SMS Provider

The SMS integration uses the Strategy pattern behind the SmsClient port. Select the provider with:

SMS_PROVIDER=kavenegar

Supported values:

  • kavenegar: uses KAVENEGAR_API_KEY and KAVENEGAR_LOGIN_TEMPLATE.
  • sms_ir: uses SMS_IR_API_KEY and SMS_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, implemented as the sibling package gapido_demo, 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

The production Docker image installs runtime dependencies only. Development tools are installed locally through .[dev].

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>

Postman

Postman helper files are available in postman/:

  • Gapido Auth gRPC.postman_environment.json
  • Gapido Auth gRPC.postman_collection.json
  • README.md with gRPC request setup steps

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
No description provided
Readme 1.1 MiB
Languages
Python 91.8%
JavaScript 3.3%
CSS 2%
HTML 2%
Dockerfile 0.5%
Other 0.4%