From 9bf32f7402094723e95483b824a42d962a30c5ba Mon Sep 17 00:00:00 2001 From: Edem Date: Fri, 15 Jul 2022 07:40:07 +0000 Subject: [PATCH 01/15] updated --- readMe.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 readMe.md diff --git a/readMe.md b/readMe.md new file mode 100644 index 0000000..1089b05 --- /dev/null +++ b/readMe.md @@ -0,0 +1,5 @@ +# RESTful API with Python, FastAPI, Pydantic, and MongoDB + +### 1. API with Python, FastAPI, and MongoDB: JWT Authentication + +[API with Python, FastAPI, and MongoDB: JWT Authentication](https://codevoweb.com/api-with-python-fastapi-and-mongodb-jwt-authentication) From e15a4260019fbafa164aab8f2c17b036715df55a Mon Sep 17 00:00:00 2001 From: Edem Date: Fri, 15 Jul 2022 11:46:21 +0000 Subject: [PATCH 02/15] updated --- app/database.py | 10 ++++++++-- app/main.py | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/database.py b/app/database.py index ed87d09..fad8ae7 100644 --- a/app/database.py +++ b/app/database.py @@ -2,8 +2,14 @@ import pymongo from app.config import settings -client = mongo_client.MongoClient(settings.DATABASE_URL) -print('Connected to MongoDB...') +client = mongo_client.MongoClient( + settings.DATABASE_URL, serverSelectionTimeoutMS=5000) + +try: + conn = client.server_info() + print(f'Connected to MongoDB {conn.get("version")}') +except Exception: + print("Unable to connect to the MongoDB server.") db = client[settings.MONGO_INITDB_DATABASE] User = db.users diff --git a/app/main.py b/app/main.py index 56028ec..bafc4ba 100644 --- a/app/main.py +++ b/app/main.py @@ -1,5 +1,6 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +import uvicorn from app.config import settings from app.routers import auth, user From b63ee2bf6b5cfd030abb547a6fd487e6468ebc11 Mon Sep 17 00:00:00 2001 From: Edem Date: Fri, 15 Jul 2022 11:48:30 +0000 Subject: [PATCH 03/15] updated --- app/schemas.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/schemas.py b/app/schemas.py index ab5166e..fa2f692 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -3,7 +3,6 @@ class UserBaseSchema(BaseModel): - id: str | None = None name: str email: str photo: str @@ -26,6 +25,11 @@ class LoginUserSchema(BaseModel): password: constr(min_length=8) +class UserResponseSchema(UserBaseSchema): + id: str + pass + + class UserResponse(BaseModel): status: str - user: UserBaseSchema + user: UserResponseSchema From f2fe543af449297304f20c51ce2e66ee3cd830fe Mon Sep 17 00:00:00 2001 From: Edem Date: Fri, 15 Jul 2022 17:18:47 +0000 Subject: [PATCH 04/15] updated --- app/main.py | 1 - app/routers/auth.py | 3 +-- app/routers/user.py | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/main.py b/app/main.py index bafc4ba..56028ec 100644 --- a/app/main.py +++ b/app/main.py @@ -1,6 +1,5 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -import uvicorn from app.config import settings from app.routers import auth, user diff --git a/app/routers/auth.py b/app/routers/auth.py index 5187a0f..5281e5b 100644 --- a/app/routers/auth.py +++ b/app/routers/auth.py @@ -1,7 +1,6 @@ from datetime import datetime, timedelta from bson.objectid import ObjectId -from fastapi import APIRouter, Request, Response, status, Depends, HTTPException -from pydantic import EmailStr +from fastapi import APIRouter, Response, status, Depends, HTTPException from app import oauth2 from app.database import User diff --git a/app/routers/user.py b/app/routers/user.py index ae1c722..b2912ef 100644 --- a/app/routers/user.py +++ b/app/routers/user.py @@ -10,5 +10,6 @@ @router.get('/me', response_model=schemas.UserResponse) def get_me(user_id: str = Depends(oauth2.require_user)): + print(User.find_one({'_id': ObjectId(str(user_id))})) user = userResponseEntity(User.find_one({'_id': ObjectId(str(user_id))})) return {"status": "success", "user": user} From 0900105719606617d8bca8a02631d63013675d0e Mon Sep 17 00:00:00 2001 From: Edem Date: Mon, 18 Jul 2022 11:26:17 +0000 Subject: [PATCH 05/15] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index 1089b05..fb75b6a 100644 --- a/readMe.md +++ b/readMe.md @@ -3,3 +3,7 @@ ### 1. API with Python, FastAPI, and MongoDB: JWT Authentication [API with Python, FastAPI, and MongoDB: JWT Authentication](https://codevoweb.com/api-with-python-fastapi-and-mongodb-jwt-authentication) + +### 2. Build API with Python & FastAPI: SignUp User and Verify Email + +[Build API with Python & FastAPI: SignUp User and Verify Email](https://codevoweb.com/api-with-python-fastapi-signup-user-and-verify-email) From 05c5e4c7f58ac5198f0bc73b2e355deaee558a7c Mon Sep 17 00:00:00 2001 From: Edem Date: Wed, 20 Jul 2022 06:14:31 +0000 Subject: [PATCH 06/15] updated --- app/oauth2.py | 2 +- app/routers/auth.py | 2 +- app/routers/user.py | 2 +- app/{serializers.py => serializers/userSerializers.py} | 9 +++++++++ 4 files changed, 12 insertions(+), 3 deletions(-) rename app/{serializers.py => serializers/userSerializers.py} (80%) diff --git a/app/oauth2.py b/app/oauth2.py index 517960f..11146cd 100644 --- a/app/oauth2.py +++ b/app/oauth2.py @@ -5,7 +5,7 @@ from pydantic import BaseModel from bson.objectid import ObjectId -from app.serializers import userEntity +from app.serializers.userSerializers import userEntity from .database import User from .config import settings diff --git a/app/routers/auth.py b/app/routers/auth.py index 5281e5b..172bd95 100644 --- a/app/routers/auth.py +++ b/app/routers/auth.py @@ -4,7 +4,7 @@ from app import oauth2 from app.database import User -from app.serializers import userEntity, userResponseEntity +from app.serializers.userSerializers import userEntity, userResponseEntity from .. import schemas, utils from app.oauth2 import AuthJWT from ..config import settings diff --git a/app/routers/user.py b/app/routers/user.py index b2912ef..600ab86 100644 --- a/app/routers/user.py +++ b/app/routers/user.py @@ -1,6 +1,6 @@ from fastapi import APIRouter, Depends from bson.objectid import ObjectId -from app.serializers import userResponseEntity +from app.serializers.userSerializers import userResponseEntity from app.database import User from .. import schemas, oauth2 diff --git a/app/serializers.py b/app/serializers/userSerializers.py similarity index 80% rename from app/serializers.py rename to app/serializers/userSerializers.py index 9a82e3f..fc25f84 100644 --- a/app/serializers.py +++ b/app/serializers/userSerializers.py @@ -24,5 +24,14 @@ def userResponseEntity(user) -> dict: } +def embeddedUserResponse(user) -> dict: + return { + "id": str(user["_id"]), + "name": user["name"], + "email": user["email"], + "photo": user["photo"] + } + + def userListEntity(users) -> list: return [userEntity(user) for user in users] From ec72f09fb4147dcf13d81530db105a215c9ccb53 Mon Sep 17 00:00:00 2001 From: Edem Date: Wed, 20 Jul 2022 10:43:42 +0000 Subject: [PATCH 07/15] updated --- readMe.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readMe.md b/readMe.md index fb75b6a..7759a39 100644 --- a/readMe.md +++ b/readMe.md @@ -7,3 +7,7 @@ ### 2. Build API with Python & FastAPI: SignUp User and Verify Email [Build API with Python & FastAPI: SignUp User and Verify Email](https://codevoweb.com/api-with-python-fastapi-signup-user-and-verify-email) + +### 3. CRUD RESTful API Server with Python, FastAPI, and MongoDB + +[CRUD RESTful API Server with Python, FastAPI, and MongoDB](https://codevoweb.com/crud-restful-api-server-with-python-fastapi-and-mongodb) From d41573a88da9802f9fd07786832797c43496a1f0 Mon Sep 17 00:00:00 2001 From: Edem Date: Sun, 28 Aug 2022 12:35:42 +0000 Subject: [PATCH 08/15] updated --- requirements.txt | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2204aa0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,56 @@ +aioredis==2.0.1 +aiosmtplib==1.1.6 +anyio==3.6.1 +asgiref==3.5.2 +async-timeout==4.0.2 +autopep8==1.6.0 +bcrypt==3.2.2 +blinker==1.4 +certifi==2022.6.15 +cffi==1.15.1 +charset-normalizer==2.1.0 +click==8.1.3 +colorama==0.4.5 +cryptography==3.4.8 +Deprecated==1.2.13 +dnspython==2.2.1 +email-validator==1.2.1 +fakeredis==1.8.1 +fastapi==0.78.0 +fastapi-jwt-auth==0.5.0 +fastapi-mail==1.0.9 +h11==0.12.0 +httpcore==0.15.0 +httptools==0.4.0 +httpx==0.23.0 +idna==3.3 +itsdangerous==2.1.2 +Jinja2==3.1.2 +MarkupSafe==2.1.1 +orjson==3.7.7 +packaging==21.3 +passlib==1.7.4 +pycodestyle==2.8.0 +pycparser==2.21 +pydantic==1.9.1 +PyJWT==1.7.1 +pymongo==4.1.1 +pyparsing==3.0.9 +python-dotenv==0.20.0 +python-multipart==0.0.5 +PyYAML==6.0 +redis==4.3.4 +requests==2.28.1 +rfc3986==1.5.0 +six==1.16.0 +sniffio==1.2.0 +sortedcontainers==2.4.0 +starlette==0.19.1 +toml==0.10.2 +typing_extensions==4.3.0 +ujson==5.4.0 +urllib3==1.26.10 +uvicorn==0.17.6 +watchgod==0.8.2 +websockets==10.3 +wrapt==1.14.1 From cf0debbd00d771885da60b93cb71e3073f82ca22 Mon Sep 17 00:00:00 2001 From: CODEVO Date: Sun, 2 Oct 2022 15:49:23 +0000 Subject: [PATCH 09/15] Update readMe.md --- readMe.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/readMe.md b/readMe.md index 7759a39..3137be8 100644 --- a/readMe.md +++ b/readMe.md @@ -1,4 +1,32 @@ -# RESTful API with Python, FastAPI, Pydantic, and MongoDB +# API with Python, FastAPI, and MongoDB: JWT Authentication + +This article will teach you how to add JSON Web Token (JWT) authentication to your FastAPI app using PyMongo, Pydantic, FastAPI JWT Auth package, and Docker-compose. + +![API with Python, FastAPI, and MongoDB: JWT Authentication](https://codevoweb.com/wp-content/uploads/2022/07/API-with-Python-FastAPI-and-MongoDB-JWT-Authentication.webp) + +## Topics Covered + +- How to Setup FastAPI with MongoDB +- Starting the FastAPI Server +- Set up Environment Variables with Pydantic +- Connect to the MongoDB Database +- Creating the Schemas with Pydantic +- Create Serializers for the MongoDB BSON Documents +- Password Management in FastAPI +- Creating Utility Functions to Sign and Verify JWTs +- Creating the Authentication Controllers in FastAPI + - User Registration Handler + - User Sign-in Handler + - Refresh Access Token Handler + - Sign out User Handler +- How to Protect Private Routes +- Creating a User Handler +- Adding the API Routes and CORS +- Testing the API with Postman + +Read the entire article here: [https://codevoweb.com/api-with-python-fastapi-and-mongodb-jwt-authentication](https://codevoweb.com/api-with-python-fastapi-and-mongodb-jwt-authentication) + +Articles in this series: ### 1. API with Python, FastAPI, and MongoDB: JWT Authentication From bf61c69712295ad97421a64949835e1fa4542aff Mon Sep 17 00:00:00 2001 From: Edem Ziddah Date: Tue, 20 Dec 2022 13:25:51 +0000 Subject: [PATCH 10/15] updated --- app/routers/auth.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/routers/auth.py b/app/routers/auth.py index 172bd95..a829d09 100644 --- a/app/routers/auth.py +++ b/app/routers/auth.py @@ -42,15 +42,11 @@ async def create_user(payload: schemas.CreateUserSchema): @router.post('/login') def login(payload: schemas.LoginUserSchema, response: Response, Authorize: AuthJWT = Depends()): # Check if the user exist - user = userEntity(User.find_one({'email': payload.email.lower()})) - if not user: + db_user = User.find_one({'email': payload.email.lower()}) + if not db_user: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail='Incorrect Email or Password') - - # Check if user verified his email - if not user['verified']: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, - detail='Please verify your email address') + user = userEntity(db_user) # Check if the password is valid if not utils.verify_password(payload.password, user['password']): From f2940f382b4ed1062930603d71168477753342ef Mon Sep 17 00:00:00 2001 From: Edem Ziddah Date: Tue, 20 Dec 2022 13:30:01 +0000 Subject: [PATCH 11/15] updated --- requirements.txt | 69 ++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/requirements.txt b/requirements.txt index 2204aa0..f806418 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,56 +1,43 @@ -aioredis==2.0.1 -aiosmtplib==1.1.6 -anyio==3.6.1 -asgiref==3.5.2 -async-timeout==4.0.2 -autopep8==1.6.0 -bcrypt==3.2.2 -blinker==1.4 -certifi==2022.6.15 +aiosmtplib==1.1.7 +anyio==3.6.2 +bcrypt==4.0.1 +blinker==1.5 +certifi==2022.12.7 cffi==1.15.1 -charset-normalizer==2.1.0 click==8.1.3 -colorama==0.4.5 +colorama==0.4.6 cryptography==3.4.8 -Deprecated==1.2.13 dnspython==2.2.1 -email-validator==1.2.1 -fakeredis==1.8.1 -fastapi==0.78.0 +ecdsa==0.18.0 +email-validator==1.3.0 +fastapi==0.88.0 fastapi-jwt-auth==0.5.0 -fastapi-mail==1.0.9 -h11==0.12.0 -httpcore==0.15.0 -httptools==0.4.0 -httpx==0.23.0 -idna==3.3 +fastapi-mail==1.1.5 +h11==0.14.0 +httpcore==0.16.2 +httptools==0.5.0 +httpx==0.23.1 +idna==3.4 itsdangerous==2.1.2 Jinja2==3.1.2 MarkupSafe==2.1.1 -orjson==3.7.7 -packaging==21.3 +orjson==3.8.3 passlib==1.7.4 -pycodestyle==2.8.0 +pyasn1==0.4.8 pycparser==2.21 -pydantic==1.9.1 +pydantic==1.10.2 PyJWT==1.7.1 -pymongo==4.1.1 -pyparsing==3.0.9 -python-dotenv==0.20.0 +pymongo==4.3.3 +python-dotenv==0.21.0 python-multipart==0.0.5 PyYAML==6.0 -redis==4.3.4 -requests==2.28.1 rfc3986==1.5.0 +rsa==4.9 six==1.16.0 -sniffio==1.2.0 -sortedcontainers==2.4.0 -starlette==0.19.1 -toml==0.10.2 -typing_extensions==4.3.0 -ujson==5.4.0 -urllib3==1.26.10 -uvicorn==0.17.6 -watchgod==0.8.2 -websockets==10.3 -wrapt==1.14.1 +sniffio==1.3.0 +starlette==0.22.0 +typing_extensions==4.4.0 +ujson==5.6.0 +uvicorn==0.20.0 +watchfiles==0.18.1 +websockets==10.4 \ No newline at end of file From 457c824f64248438580a4c598ef4aa093a28c522 Mon Sep 17 00:00:00 2001 From: Edem Ziddah Date: Tue, 20 Dec 2022 19:28:30 +0000 Subject: [PATCH 12/15] updated --- requirements.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index f806418..85c1279 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ aiosmtplib==1.1.7 anyio==3.6.2 +autopep8==2.0.1 bcrypt==4.0.1 blinker==1.5 certifi==2022.12.7 @@ -12,7 +13,7 @@ ecdsa==0.18.0 email-validator==1.3.0 fastapi==0.88.0 fastapi-jwt-auth==0.5.0 -fastapi-mail==1.1.5 +fastapi-mail==1.2.2 h11==0.14.0 httpcore==0.16.2 httptools==0.5.0 @@ -24,6 +25,7 @@ MarkupSafe==2.1.1 orjson==3.8.3 passlib==1.7.4 pyasn1==0.4.8 +pycodestyle==2.10.0 pycparser==2.21 pydantic==1.10.2 PyJWT==1.7.1 @@ -35,9 +37,9 @@ rfc3986==1.5.0 rsa==4.9 six==1.16.0 sniffio==1.3.0 -starlette==0.22.0 +starlette==0.21.0 typing_extensions==4.4.0 ujson==5.6.0 uvicorn==0.20.0 watchfiles==0.18.1 -websockets==10.4 \ No newline at end of file +websockets==10.4 From a9a222b6ea2ef1d63a42fdfd77bd7551bb53a28b Mon Sep 17 00:00:00 2001 From: CODEVO Date: Thu, 22 Dec 2022 06:20:18 +0000 Subject: [PATCH 13/15] updated --- Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9de29e1..33b1a11 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,10 @@ dev: docker-compose up -d dev-down: - docker-compose down \ No newline at end of file + docker-compose down + +start-server: + uvicorn app.main:app --reload + +install-modules: + pip install fastapi[all] fastapi-mail==1.2.2 fastapi-jwt-auth[asymmetric] passlib[bcrypt] pymongo \ No newline at end of file From 2128448c08bee8935365d17fd605b97414554a0f Mon Sep 17 00:00:00 2001 From: CODEVO Date: Thu, 22 Dec 2022 17:25:23 +0000 Subject: [PATCH 14/15] updated --- requirements.txt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index 85c1279..c822130 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ aiosmtplib==1.1.7 anyio==3.6.2 -autopep8==2.0.1 bcrypt==4.0.1 blinker==1.5 certifi==2022.12.7 @@ -9,13 +8,12 @@ click==8.1.3 colorama==0.4.6 cryptography==3.4.8 dnspython==2.2.1 -ecdsa==0.18.0 email-validator==1.3.0 -fastapi==0.88.0 +fastapi==0.87.0 fastapi-jwt-auth==0.5.0 fastapi-mail==1.2.2 h11==0.14.0 -httpcore==0.16.2 +httpcore==0.16.3 httptools==0.5.0 httpx==0.23.1 idna==3.4 @@ -24,8 +22,6 @@ Jinja2==3.1.2 MarkupSafe==2.1.1 orjson==3.8.3 passlib==1.7.4 -pyasn1==0.4.8 -pycodestyle==2.10.0 pycparser==2.21 pydantic==1.10.2 PyJWT==1.7.1 @@ -34,7 +30,6 @@ python-dotenv==0.21.0 python-multipart==0.0.5 PyYAML==6.0 rfc3986==1.5.0 -rsa==4.9 six==1.16.0 sniffio==1.3.0 starlette==0.21.0 From 064285baa67d35df075aebc6db4284f08beb0606 Mon Sep 17 00:00:00 2001 From: CODEVO Date: Thu, 29 Dec 2022 18:05:24 +0000 Subject: [PATCH 15/15] updated --- Makefile | 2 +- app/routers/user.py | 1 - requirements.txt | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 33b1a11..3dfab37 100644 --- a/Makefile +++ b/Makefile @@ -8,4 +8,4 @@ start-server: uvicorn app.main:app --reload install-modules: - pip install fastapi[all] fastapi-mail==1.2.2 fastapi-jwt-auth[asymmetric] passlib[bcrypt] pymongo \ No newline at end of file + pip install fastapi[all] fastapi-mail fastapi-jwt-auth[asymmetric] passlib[bcrypt] pymongo \ No newline at end of file diff --git a/app/routers/user.py b/app/routers/user.py index 600ab86..46a5917 100644 --- a/app/routers/user.py +++ b/app/routers/user.py @@ -10,6 +10,5 @@ @router.get('/me', response_model=schemas.UserResponse) def get_me(user_id: str = Depends(oauth2.require_user)): - print(User.find_one({'_id': ObjectId(str(user_id))})) user = userResponseEntity(User.find_one({'_id': ObjectId(str(user_id))})) return {"status": "success", "user": user} diff --git a/requirements.txt b/requirements.txt index c822130..0630b1c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ aiosmtplib==1.1.7 anyio==3.6.2 +autopep8==2.0.1 bcrypt==4.0.1 blinker==1.5 certifi==2022.12.7 @@ -22,6 +23,7 @@ Jinja2==3.1.2 MarkupSafe==2.1.1 orjson==3.8.3 passlib==1.7.4 +pycodestyle==2.10.0 pycparser==2.21 pydantic==1.10.2 PyJWT==1.7.1