A production-ready backend wallet service built with FastAPI, featuring Google OAuth authentication, API key management, Paystack payment integration, and wallet-to-wallet transfers.
-
Dual Authentication
- Google OAuth 2.0 sign-in with JWT tokens
- Username/password authentication (backup)
-
API Key Management
- Permission-based access (deposit, transfer, read)
- Flexible expiry formats (1H, 1D, 1M, 1Y)
- Maximum 5 active keys per user
- API key rollover for expired keys
-
Wallet Operations
- Automatic wallet creation on user registration
- Unique 13-digit wallet numbers
- Real-time balance tracking
- Transaction history with pagination
-
Paystack Integration
- Deposit initialization with payment links
- Mandatory webhook handling for automatic crediting
- Webhook signature validation
- Idempotent transaction processing
-
Wallet Transfers
- Atomic wallet-to-wallet transfers
- Balance validation
- Self-transfer prevention
- Dual transaction recording (OUT/IN)
-
Security
- HMAC-SHA512 webhook signature verification
- bcrypt password hashing
- JWT token-based authentication
- API key permission enforcement
- CORS configuration
- Python 3.12+
- PostgreSQL 14+
- Paystack account (test/live keys)
- Google OAuth credentials (optional)
git clone https://github.com/Imuaz/hng-be-s8.git
cd hng-be-s8python3.12 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activatepip install -r requirements.txtcp .env.example .env
# Edit .env with your credentialsRequired variables:
DATABASE_URL=postgresql://user:password@localhost:5432/wallet_db
SECRET_KEY=your-secret-key-minimum-32-characters
PAYSTACK_SECRET_KEY=sk_test_your_paystack_secret
PAYSTACK_PUBLIC_KEY=pk_test_your_paystack_public
# Optional (for Google OAuth)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_REDIRECT_URI=http://localhost:8000/auth/google/callback# Create database
createdb wallet_db
# Run migrations
alembic upgrade headuvicorn main:app --reloadServer runs at: http://localhost:8000
API Documentation: http://localhost:8000/docs
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| GET | /auth/google |
Initiate Google OAuth | None |
| GET | /auth/google/callback |
OAuth callback, returns JWT | None |
| POST | /auth/signup |
Create account | None |
| POST | /auth/login |
Login, returns JWT | None |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| POST | /keys/create |
Create API key | JWT |
| POST | /keys/rollover |
Rollover expired key | JWT |
| GET | /keys |
List user's API keys | JWT |
| DELETE | /keys/{key_id} |
Revoke API key | JWT |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| GET | /wallet/balance |
Get wallet balance | JWT or API key (read) |
| POST | /wallet/deposit |
Initialize Paystack deposit | JWT or API key (deposit) |
| POST | /wallet/paystack/webhook |
Paystack webhook handler | Webhook signature |
| GET | /wallet/deposit/{ref}/status |
Check deposit status | JWT or API key (read) |
| POST | /wallet/transfer |
Transfer to another wallet | JWT or API key (transfer) |
| GET | /wallet/transactions |
Transaction history | JWT or API key (read) |
# 1. Login
curl -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"user","password":"pass"}'
# Response: {"access_token": "eyJ...", "token_type": "bearer"}
# 2. Use token
curl http://localhost:8000/wallet/balance \
-H "Authorization: Bearer eyJ..."# 1. Create API key
curl -X POST http://localhost:8000/keys/create \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{
"name": "wallet-service",
"permissions": ["deposit", "transfer", "read"],
"expiry": "1M"
}'
# Response: {"api_key": "sk_...", "expires_at": "..."}
# 2. Use API key
curl http://localhost:8000/wallet/balance \
-H "x-api-key: sk_..."# Initialize deposit
curl -X POST http://localhost:8000/wallet/deposit \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"amount": 5000}'
# Response includes Paystack payment link
{
"reference": "DEP-xxxxx",
"authorization_url": "https://checkout.paystack.com/xxxxx",
"access_code": "xxxxx"
}
# User completes payment β Paystack sends webhook β Wallet credited automaticallycurl -X POST http://localhost:8000/wallet/transfer \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"wallet_number": "1234567890123",
"amount": 1000
}'curl http://localhost:8000/wallet/transactions?limit=20&offset=0 \
-H "Authorization: Bearer YOUR_TOKEN"- Go to Paystack Dashboard
- Set webhook URL:
https://your-domain.com/wallet/paystack/webhook - Select events: All Events or Successful Payment
- Save
For local testing:
- Use ngrok:
ngrok http 8000 - Update webhook to:
https://your-ngrok-url.ngrok.io/wallet/paystack/webhook
- Go to Google Cloud Console
- Create OAuth 2.0 credentials
- Add authorized redirect URI:
http://localhost:8000/auth/google/callback - Copy Client ID and Client Secret to
.env
pytestUse Swagger UI at http://localhost:8000/docs
Card Number: 4084084084084081
CVV: 408
Expiry: Any future date
PIN: 0000
OTP: 123456
hng-be-s8/
βββ app/
β βββ dependencies/ # Auth dependencies
β βββ models/ # SQLAlchemy models
β βββ routers/ # API endpoints
β βββ schemas/ # Pydantic schemas
β βββ services/ # Business logic
β βββ utils/ # Helper functions
β βββ config.py # Configuration
β βββ database.py # Database setup
βββ migrations/ # Alembic migrations
βββ main.py # FastAPI application
βββ requirements.txt # Python dependencies
βββ .env.example # Environment template
βββ Procfile # Railway/Heroku config
βββ README.md # This file
- β Password hashing with bcrypt
- β JWT token authentication
- β API key permission validation
- β Webhook signature verification (HMAC-SHA512)
- β CORS configuration
- β SQL injection protection (SQLAlchemy)
- β Environment variable secrets
- β Idempotent webhook processing
- β Atomic database transactions
- read: View balance, transactions
- deposit: Initialize deposits
- transfer: Transfer funds
- Framework: FastAPI 0.104.1
- Database: PostgreSQL with SQLAlchemy
- Authentication: JWT (PyJWT), OAuth (Authlib)
- Payments: Paystack API
- Password Hashing: bcrypt
- Migrations: Alembic
- ASGI Server: Uvicorn
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License.
Imuaz
- GitHub: @Imuaz
- FastAPI - Modern web framework
- Paystack - Payment infrastructure
- HNG Internship - Project requirements
For support, email me or open an issue.
Built with β€οΈ for HNG Internship Stage 8