diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index deb722b96..f6ed2bfe9 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -218,6 +218,8 @@ Update `get_current_user` to receive the same token as before, but this time, us Decode the received token, verify it, and return the current user. +Note: jwt.decode has a built-in method to check "exp" and it does check it by default (https://github.com/mpdavis/python-jose/blob/96474ecfb6ad3ce16f41b0814ab5126d58725e2a/jose/jwt.py#L82) + If the token is invalid, return an HTTP error right away. === "Python 3.10+" diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004.py index 64099abe9..904281489 100644 --- a/docs_src/security/tutorial004.py +++ b/docs_src/security/tutorial004.py @@ -3,7 +3,7 @@ from typing import Union from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jose import JWTError, jwt +from jose import ExpiredSignatureError, JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel @@ -89,7 +89,7 @@ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None async def get_current_user(token: str = Depends(oauth2_scheme)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", + detail="Could not validate credentials or signature has expired", headers={"WWW-Authenticate": "Bearer"}, ) try: @@ -98,6 +98,8 @@ async def get_current_user(token: str = Depends(oauth2_scheme)): if username is None: raise credentials_exception token_data = TokenData(username=username) + except ExpiredSignatureError: # Check signature expiry + raise credentials_exception except JWTError: raise credentials_exception user = get_user(fake_users_db, username=token_data.username) diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py index ca350343d..370acec45 100644 --- a/docs_src/security/tutorial004_an.py +++ b/docs_src/security/tutorial004_an.py @@ -3,7 +3,7 @@ from typing import Union from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jose import JWTError, jwt +from jose import ExpiredSignatureError, JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel from typing_extensions import Annotated @@ -90,7 +90,7 @@ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", + detail="Could not validate credentials or signature has expired", headers={"WWW-Authenticate": "Bearer"}, ) try: @@ -99,6 +99,8 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): if username is None: raise credentials_exception token_data = TokenData(username=username) + except ExpiredSignatureError: # Check signature expiry + raise credentials_exception except JWTError: raise credentials_exception user = get_user(fake_users_db, username=token_data.username) diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py index 8bf5f3b71..487f9b168 100644 --- a/docs_src/security/tutorial004_an_py310.py +++ b/docs_src/security/tutorial004_an_py310.py @@ -3,7 +3,7 @@ from typing import Annotated from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jose import JWTError, jwt +from jose import ExpiredSignatureError, JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel @@ -89,7 +89,7 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None): async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", + detail="Could not validate credentials or signature has expired", headers={"WWW-Authenticate": "Bearer"}, ) try: @@ -98,6 +98,8 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): if username is None: raise credentials_exception token_data = TokenData(username=username) + except ExpiredSignatureError: # Check signature expiry + raise credentials_exception except JWTError: raise credentials_exception user = get_user(fake_users_db, username=token_data.username) diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py index a634e23de..e68281880 100644 --- a/docs_src/security/tutorial004_an_py39.py +++ b/docs_src/security/tutorial004_an_py39.py @@ -3,7 +3,7 @@ from typing import Annotated, Union from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jose import JWTError, jwt +from jose import ExpiredSignatureError, JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel @@ -89,7 +89,7 @@ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", + detail="Could not validate credentials or signature has expired", headers={"WWW-Authenticate": "Bearer"}, ) try: @@ -98,6 +98,8 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): if username is None: raise credentials_exception token_data = TokenData(username=username) + except ExpiredSignatureError: # Check signature expiry + raise credentials_exception except JWTError: raise credentials_exception user = get_user(fake_users_db, username=token_data.username) diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py index 797d56d04..8e4aafd82 100644 --- a/docs_src/security/tutorial004_py310.py +++ b/docs_src/security/tutorial004_py310.py @@ -2,7 +2,7 @@ from datetime import datetime, timedelta from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jose import JWTError, jwt +from jose import ExpiredSignatureError, JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel @@ -88,7 +88,7 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None): async def get_current_user(token: str = Depends(oauth2_scheme)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", + detail="Could not validate credentials or signature has expired", headers={"WWW-Authenticate": "Bearer"}, ) try: @@ -97,6 +97,8 @@ async def get_current_user(token: str = Depends(oauth2_scheme)): if username is None: raise credentials_exception token_data = TokenData(username=username) + except ExpiredSignatureError: # Check signature expiry + raise credentials_exception except JWTError: raise credentials_exception user = get_user(fake_users_db, username=token_data.username)