Skip to content

Commit 1c24bc5

Browse files
author
IndominusByte
committed
add config cookie jwt
1 parent e67db4b commit 1c24bc5

File tree

4 files changed

+239
-121
lines changed

4 files changed

+239
-121
lines changed

fastapi_jwt_auth/auth_config.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def load_config(cls, settings: Callable[...,List[tuple]]) -> "AuthConfig":
5959
try:
6060
config = LoadConfig(**{key.lower():value for key,value in settings()})
6161

62+
cls._token_location = config.authjwt_token_location
6263
cls._secret_key = config.authjwt_secret_key
6364
cls._public_key = config.authjwt_public_key
6465
cls._private_key = config.authjwt_private_key
@@ -74,6 +75,24 @@ def load_config(cls, settings: Callable[...,List[tuple]]) -> "AuthConfig":
7475
cls._header_type = config.authjwt_header_type
7576
cls._access_token_expires = config.authjwt_access_token_expires
7677
cls._refresh_token_expires = config.authjwt_refresh_token_expires
78+
# option for create cookies
79+
cls._access_cookie_key = config.authjwt_access_cookie_key
80+
cls._refresh_cookie_key = config.authjwt_refresh_cookie_key
81+
cls._access_cookie_path = config.authjwt_access_cookie_path
82+
cls._refresh_cookie_path = config.authjwt_refresh_cookie_path
83+
cls._cookie_max_age = config.authjwt_cookie_max_age
84+
cls._cookie_domain = config.authjwt_cookie_domain
85+
cls._cookie_secure = config.authjwt_cookie_secure
86+
cls._cookie_samesite = config.authjwt_cookie_samesite
87+
# option for double submit csrf protection
88+
cls._cookie_csrf_protect = config.authjwt_cookie_csrf_protect
89+
cls._access_csrf_cookie_key = config.authjwt_access_csrf_cookie_key
90+
cls._refresh_csrf_cookie_key = config.authjwt_refresh_csrf_cookie_key
91+
cls._access_csrf_cookie_path = config.authjwt_access_csrf_cookie_path
92+
cls._refresh_csrf_cookie_path = config.authjwt_refresh_csrf_cookie_path
93+
cls._access_csrf_header_name = config.authjwt_access_csrf_header_name
94+
cls._refresh_csrf_header_name = config.authjwt_refresh_csrf_header_name
95+
cls._csrf_methods = config.authjwt_csrf_methods
7796
except ValidationError:
7897
raise
7998
except Exception:

fastapi_jwt_auth/config.py

Lines changed: 46 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
from datetime import timedelta
22
from typing import Optional, Union, Sequence, List
3-
from types import GeneratorType
43
from pydantic import (
54
BaseModel,
6-
root_validator,
75
validator,
86
StrictBool,
97
StrictInt,
108
StrictStr
119
)
1210

1311
class LoadConfig(BaseModel):
12+
authjwt_token_location: Optional[Sequence[StrictStr]] = {'headers'}
1413
authjwt_secret_key: Optional[StrictStr] = None
1514
authjwt_public_key: Optional[StrictStr] = None
1615
authjwt_private_key: Optional[StrictStr] = None
@@ -26,91 +25,59 @@ class LoadConfig(BaseModel):
2625
authjwt_header_type: Optional[StrictStr] = "Bearer"
2726
authjwt_access_token_expires: Optional[Union[StrictBool,StrictInt,timedelta]] = timedelta(minutes=15)
2827
authjwt_refresh_token_expires: Optional[Union[StrictBool,StrictInt,timedelta]] = timedelta(days=30)
28+
# option for create cookies
29+
authjwt_access_cookie_key: Optional[StrictStr] = "access_token_cookie"
30+
authjwt_refresh_cookie_key: Optional[StrictStr] = "refresh_token_cookie"
31+
authjwt_access_cookie_path: Optional[StrictStr] = "/"
32+
authjwt_refresh_cookie_path: Optional[StrictStr] = "/"
33+
authjwt_cookie_max_age: Optional[StrictInt] = None
34+
authjwt_cookie_domain: Optional[StrictStr] = None
35+
authjwt_cookie_secure: Optional[StrictBool] = False
36+
authjwt_cookie_samesite: Optional[StrictStr] = "lax"
37+
# option for double submit csrf protection
38+
authjwt_cookie_csrf_protect: Optional[StrictBool] = True
39+
authjwt_access_csrf_cookie_key: Optional[StrictStr] = "csrf_access_token"
40+
authjwt_refresh_csrf_cookie_key: Optional[StrictStr] = "csrf_refresh_token"
41+
authjwt_access_csrf_cookie_path: Optional[StrictStr] = "/"
42+
authjwt_refresh_csrf_cookie_path: Optional[StrictStr] = "/"
43+
authjwt_access_csrf_header_name: Optional[StrictStr] = "X-CSRF-Token"
44+
authjwt_refresh_csrf_header_name: Optional[StrictStr] = "X-CSRF-Token"
45+
authjwt_csrf_methods: Optional[Sequence[StrictStr]] = {'POST','PUT','PATCH','DELETE'}
46+
47+
@validator('authjwt_access_token_expires')
48+
def validate_access_token_expires(cls, v):
49+
if v is True:
50+
raise ValueError("The 'authjwt_access_token_expires' only accept value False (bool)")
51+
return v
2952

30-
@root_validator(pre=True)
31-
def validate_all_config(cls, values):
32-
_secret_key = values.get("authjwt_secret_key")
33-
_public_key = values.get("authjwt_public_key")
34-
_private_key = values.get("authjwt_private_key")
35-
_algorithm = values.get("authjwt_algorithm")
36-
_decode_algorithms = values.get("authjwt_decode_algorithms")
37-
_decode_leeway = values.get("authjwt_decode_leeway")
38-
_encode_issuer = values.get("authjwt_encode_issuer")
39-
_decode_issuer = values.get("authjwt_decode_issuer")
40-
_decode_audience = values.get("authjwt_decode_audience")
41-
_denylist_enabled = values.get("authjwt_denylist_enabled")
42-
_denylist_token_checks = values.get("authjwt_denylist_token_checks")
43-
_header_name = values.get("authjwt_header_name")
44-
_header_type = values.get("authjwt_header_type")
45-
_access_token_expires = values.get("authjwt_access_token_expires")
46-
_refresh_token_expires = values.get("authjwt_refresh_token_expires")
47-
48-
if _secret_key and not isinstance(_secret_key, str):
49-
raise TypeError("The 'AUTHJWT_SECRET_KEY' must be a string")
50-
51-
if _public_key and not isinstance(_public_key, str):
52-
raise TypeError("The 'AUTHJWT_PUBLIC_KEY' must be a string")
53-
54-
if _private_key and not isinstance(_private_key, str):
55-
raise TypeError("The 'AUTHJWT_PRIVATE_KEY' must be a string")
56-
57-
if _algorithm and not isinstance(_algorithm, str):
58-
raise TypeError("The 'AUTHJWT_ALGORITHM' must be a string")
59-
60-
if _decode_algorithms and not isinstance(_decode_algorithms, list):
61-
raise TypeError("The 'AUTHJWT_DECODE_ALGORITHMS' must be a list")
62-
63-
if _decode_leeway and not isinstance(_decode_leeway, (timedelta, int)):
64-
raise TypeError("The 'AUTHJWT_DECODE_LEEWAY' must be a timedelta or integer")
65-
66-
if _encode_issuer and not isinstance(_encode_issuer, str):
67-
raise TypeError("The 'AUTHJWT_ENCODE_ISSUER' must be a string")
68-
69-
if _decode_issuer and not isinstance(_decode_issuer, str):
70-
raise TypeError("The 'AUTHJWT_DECODE_ISSUER' must be a string")
71-
72-
if (
73-
_decode_audience and
74-
not isinstance(_decode_audience, (str, list, tuple, set, frozenset, GeneratorType))
75-
):
76-
raise TypeError("The 'AUTHJWT_DECODE_AUDIENCE' must be a string or sequence")
77-
78-
if _denylist_enabled and not isinstance(_denylist_enabled, bool):
79-
raise TypeError("The 'AUTHJWT_DENYLIST_ENABLED' must be a boolean")
80-
81-
if (
82-
_denylist_token_checks and
83-
not isinstance(_denylist_token_checks, (list, tuple, set, frozenset, GeneratorType))
84-
):
85-
raise TypeError("The 'AUTHJWT_DENYLIST_TOKEN_CHECKS' must be a sequence")
86-
87-
if _header_name and not isinstance(_header_name, str):
88-
raise TypeError("The 'AUTHJWT_HEADER_NAME' must be a string")
89-
90-
if _header_type and not isinstance(_header_type, str):
91-
raise TypeError("The 'AUTHJWT_HEADER_TYPE' must be a string")
92-
93-
if _access_token_expires and not isinstance(_access_token_expires, (timedelta,int,bool)):
94-
raise TypeError("The 'AUTHJWT_ACCESS_TOKEN_EXPIRES' must be between timedelta, int, bool")
95-
96-
if _access_token_expires and _access_token_expires is True:
97-
raise TypeError("The 'AUTHJWT_ACCESS_TOKEN_EXPIRES' only accept value False")
98-
99-
if _refresh_token_expires and not isinstance(_refresh_token_expires, (timedelta,int,bool)):
100-
raise TypeError("The 'AUTHJWT_REFRESH_TOKEN_EXPIRES' must be between timedelta, int, bool")
101-
102-
if _refresh_token_expires and _refresh_token_expires is True:
103-
raise TypeError("The 'AUTHJWT_REFRESH_TOKEN_EXPIRES' only accept value False")
104-
105-
return values
53+
@validator('authjwt_refresh_token_expires')
54+
def validate_refresh_token_expires(cls, v):
55+
if v is True:
56+
raise ValueError("The 'authjwt_refresh_token_expires' only accept value False (bool)")
57+
return v
10658

10759
@validator('authjwt_denylist_token_checks', each_item=True)
10860
def validate_denylist_token_checks(cls, v):
10961
if v not in ['access','refresh']:
110-
raise ValueError("The 'AUTHJWT_DENYLIST_TOKEN_CHECKS' must be between 'access' or 'refresh'")
62+
raise ValueError("The 'authjwt_denylist_token_checks' must be between 'access' or 'refresh'")
63+
return v
11164

65+
@validator('authjwt_token_location', each_item=True)
66+
def validate_token_location(cls, v):
67+
if v not in ['headers','cookies']:
68+
raise ValueError("The 'authjwt_token_location' must be between 'headers' or 'cookies'")
11269
return v
11370

71+
@validator('authjwt_cookie_samesite')
72+
def validate_cookie_samesite(cls, v):
73+
if v not in ['strict','lax','none']:
74+
raise ValueError("The 'authjwt_cookie_samesite' must be between 'strict', 'lax', 'none'")
75+
return v
76+
77+
@validator('authjwt_csrf_methods', each_item=True)
78+
def validate_csrf_methods(cls, v):
79+
return v.upper()
80+
11481
class Config:
11582
min_anystr_length = 1
11683
anystr_strip_whitespace = True

0 commit comments

Comments
 (0)