And another one to authenticate and return a user.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
+
+When `authenticate_user` is called with a username that doesn't exist in the database, we still run `verify_password` against a dummy hash.
+
+This ensures the endpoint takes roughly the same amount of time to respond whether the username is valid or not, preventing **timing attacks** that could be used to enumerate existing usernames.
/// note
Create a utility function to generate a new access token.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
## Update the dependencies { #update-the-dependencies }
If the token is invalid, return an HTTP error right away.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
## Update the `/token` *path operation* { #update-the-token-path-operation }
Create a real JWT access token and return it.
-{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
### Technical details about the JWT "subject" `sub` { #technical-details-about-the-jwt-subject-sub }
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False
password_hash = PasswordHash.recommended()
+DUMMY_HASH = password_hash.hash("dummypassword")
+
oauth2_scheme = OAuth2PasswordBearer(
tokenUrl="token",
scopes={"me": "Read information about the current user.", "items": "Read items."},
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
+ verify_password(password, DUMMY_HASH)
return False
if not verify_password(password, user.hashed_password):
return False