A FastAPI-based multi-tenant notes application with JWT authentication and role-based access control. This API allows multiple organizations to manage their users and notes independently with strict tenant isolation.
- Multi-Tenant Architecture: Complete isolation between organizations
- JWT Authentication: Secure token-based authentication
- Role-Based Access Control: Three user roles with different permissions
- Async MongoDB: High-performance async database operations
- Comprehensive Testing: Full test coverage with pytest
- Docker Support: Easy deployment with Docker and Docker Compose
- RESTful API: Clean, well-documented REST endpoints
- Automatic Admin Creation: Organization creators automatically become admins
| Component | Technology |
|---|---|
| Framework | FastAPI |
| Database | MongoDB with Motor async driver |
| ODM | Beanie (MongoDB ODM) |
| Authentication | JWT tokens |
| Password Hashing | Bcrypt |
| Testing | Pytest (async support) |
| Containerization | Docker & Docker Compose |
- Python 3.8+
- MongoDB 4.4+
- (Optional) Docker & Docker Compose
git clone https://github.com/Emmanuelprime/Multi-Tenant-Notes-API.git
cd notes-apidocker-compose up --build- API: http://localhost:8000
- Interactive Docs: http://localhost:8000/docs
- Alternative Docs: http://localhost:8000/redoc
- Alternative Docs (Scalar): http://localhost:8000/scalar
git https://github.com/Emmanuelprime/Multi-Tenant-Notes-API.git
python -m venv venv
source venv/bin/activate pip install -r requirements.txtexport MONGO_URL="mongodb://localhost:27017"
export MONGO_DB="notes_api"
export JWT_SECRET="************************"# Using Docker
docker run -d -p 27017:27017 --name mongo mongo:7.0
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000When you create an organization, you automatically become the admin user.
curl -X POST "http://localhost:8000/organizations/" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"description": "A sample organization",
"admin_email": "admin@acme.com",
"admin_password": "admin123",
"admin_name": "John Admin"
}'Response:
{
"id": "org_id_here",
"name": "Acme Corp",
"description": "A sample organization",
"admin_user": {
"id": "user_id_here",
"email": "admin@acme.com",
"name": "John Admin",
"role": "admin"
},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}π‘ Save the id from the response β this is your organization ID.
Authenticate a user within a specific organization.
curl -X POST "http://localhost:8000/auth/login/ORG_ID_HERE" \
-H "Content-Type: application/json" \
-d '{
"email": "admin@acme.com",
"password": "admin123"
}'Response:
{
"access_token": "jwt_token_here",
"token_type": "bearer",
"user": {
"id": "user_id_here",
"email": "admin@acme.com",
"name": "John Admin",
"role": "admin",
"organization_id": "org_id_here",
"is_active": true,
"created_at": "2024-01-15T10:30:00Z"
}
}π‘ Save the access_token for authenticated requests.
Admins can create new users within their organization.
curl -X POST "http://localhost:8000/organizations/ORG_ID_HERE/users/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer JWT_TOKEN_HERE" \
-d '{
"email": "writer@acme.com",
"password": "writer123",
"name": "Jane Writer",
"role": "writer"
}'curl -X POST "http://localhost:8000/notes/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer JWT_TOKEN_HERE" \
-d '{
"title": "My First Note",
"content": "This is the content of my note"
}'curl -X GET "http://localhost:8000/notes/" \
-H "Authorization: Bearer JWT_TOKEN_HERE"curl -X GET "http://localhost:8000/notes/NOTE_ID_HERE" \
-H "Authorization: Bearer JWT_TOKEN_HERE"(Writers can update their own notes, Admins can update any.)
curl -X PUT "http://localhost:8000/notes/NOTE_ID_HERE" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer JWT_TOKEN_HERE" \
-d '{
"title": "Updated Title",
"content": "Updated content"
}'curl -X DELETE "http://localhost:8000/notes/NOTE_ID_HERE" \
-H "Authorization: Bearer JWT_TOKEN_HERE"curl -X GET "http://localhost:8000/organizations/ORG_ID_HERE/users/" \
-H "Authorization: Bearer JWT_TOKEN_HERE"curl -X PUT "http://localhost:8000/organizations/ORG_ID_HERE/users/USER_ID_HERE" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer JWT_TOKEN_HERE" \
-d '{"role": "admin"}'curl -X DELETE "http://localhost:8000/organizations/ORG_ID_HERE/users/USER_ID_HERE" \
-H "Authorization: Bearer JWT_TOKEN_HERE"| Permission | Reader | Writer | Admin |
|---|---|---|---|
| View notes | β | β | β |
| Create notes | β | β | β |
| Update own notes | β | β | β |
| Update others' notes | β | β | β |
| Delete notes | β | β | β |
| List users | β | β | β |
| Create users | β | β | β |
| Update user roles | β | β | β |
| Delete users | β | β | β |
- id: Unique identifier
- name: Organization name
- description: Organization description
- created_at, updated_at: Timestamps
- id: Unique identifier
- email: User email (unique within organization)
- password: Hashed password
- name: Userβs full name
- role: One of
"reader","writer","admin" - organization_id: Reference to organization
- is_active: Account status
- created_at, updated_at: Timestamps
- id: Unique identifier
- title: Note title
- content: Note content
- organization_id: Reference to organization
- created_by: Reference to user who created the note
- created_at, updated_at: Timestamps
pytestpytest --cov=app --cov-report=htmlpytest tests/test_auth.py -vpytest tests/test_organizations.py -vpytest tests/test_users.py -vpytest tests/test_notes.py -vpytest tests/test_permissions.py -v