IndominusByte / fastapi-jwt-auth

FastAPI extension that provides JWT Auth support (secure, easy to use, and lightweight)
http://indominusbyte.github.io/fastapi-jwt-auth/
MIT License
643 stars 149 forks source link

TypeError: `@validator(..., each_item=True)` cannot be applied to fields with a schema of json-or-python #98

Open genievn opened 1 year ago

genievn commented 1 year ago

Hi, I'm getting this error when running the example https://indominusbyte.github.io/fastapi-jwt-auth/usage/basic/

Traceback (most recent call last):
  File "/Users/kang/Dev/fastapi-jwt-test/main.py", line 3, in <module>
    from fastapi_jwt_auth import AuthJWT
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/fastapi_jwt_auth/__init__.py", line 5, in <module>
    from .auth_jwt import AuthJWT
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/fastapi_jwt_auth/auth_jwt.py", line 6, in <module>
    from fastapi_jwt_auth.auth_config import AuthConfig
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/fastapi_jwt_auth/auth_config.py", line 1, in <module>
    from fastapi_jwt_auth.config import LoadConfig
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/fastapi_jwt_auth/config.py", line 11, in <module>
    class LoadConfig(BaseModel):
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_model_construction.py", line 172, in __new__
    complete_model_class(
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_model_construction.py", line 420, in complete_model_class
    schema = cls.__get_pydantic_core_schema__(cls, handler)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/main.py", line 533, in __get_pydantic_core_schema__
    return __handler(__source)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_schema_generation_shared.py", line 82, in __call__
    schema = self._handler(__source_type)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 266, in generate_schema
    return self._generate_schema_for_type(
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 287, in _generate_schema_for_type
    schema = self._generate_schema(obj)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 477, in _generate_schema
    return self._model_schema(obj)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 353, in _model_schema
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 353, in <dictcomp>
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 618, in _generate_md_field_schema
    common_field = self._common_field_schema(name, field_info, decorators)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 674, in _common_field_schema
    schema = apply_each_item_validators(schema, each_item_validators, name)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 150, in apply_each_item_validators
    schema['schema'] = apply_each_item_validators(schema['schema'], each_item_validators, field_name)
  File "/Users/kang/Dev/fastapi-jwt-test/.venv/lib/python3.10/site-packages/pydantic/_internal/_generate_schema.py", line 165, in apply_each_item_validators
    raise TypeError(
TypeError: `@validator(..., each_item=True)` cannot be applied to fields with a schema of json-or-python

Please help. Thank you!

alejorodriguez96 commented 1 year ago

Hello!

The same problem here when updating to fastapi==0.100.0 and pydantic==2.0.2.

lbenno commented 1 year ago

I get this error simply by importing fastapi_jwt_auth or any fastapi_jwt_auth Class. Even if the package/Class is not called.

fastapi==0.100.0
fastapi_jwt_auth==0.5.0
pydantic==2.0.2
Brandl commented 1 year ago

For me I could fix the issue by downgrading to:

fastapi==0.99.1
fastapi_jwt_auth==0.5.0
pydantic==1.10.11 

Since this repo has not seen any movement in two years, this might be the only solution available until a fork appears.

subut0n commented 1 year ago

For me I could fix the issue by downgrading to:

fastapi==0.99.1
fastapi_jwt_auth==0.5.0
pydantic==1.10.11 

Since this repo has not seen any movement in two years, this might be the only solution available until a fork appears.

Hey, I am also blocked right now by this problem. I can't downgrade the packages for some project reasons. I think I will also need an alternative or build my own solution. Hope to see an update on this lol. If anyone has a solution for this, ping me please

georg-mayer commented 1 year ago

I get the very same error.

thanks for the workaround, which does the job for me for the moment.

brouberol commented 1 year ago

@georg-mayer If that can help, this PR shows how I migrated a project of mine from fastapi-jwt-auth to fastapi-jwt to circumvent this issue. With pydantic 2.0.0 being out and fastapi-jwt-auth not having been updated for the past 3 years, I think this might be a good way forward.

madmanRE commented 1 year ago

For me I could fix the issue by downgrading to:

fastapi==0.99.1
fastapi_jwt_auth==0.5.0
pydantic==1.10.11 

Since this repo has not seen any movement in two years, this might be the only solution available until a fork appears.

thx for solution!

Wallfacer005CN commented 1 year ago

Same issue

chengdujin commented 11 months ago

Any good replacement for fastapi-jwt-auth?

thuyng-ing commented 10 months ago

Any good replacement for fastapi-jwt-auth?

No, the last time, I used https://github.com/GlitchCorp/fastapi-another-jwt-auth as an alternative but seems like the maintainer abandoned it.

brouberol commented 10 months ago

To re-iterate https://github.com/IndominusByte/fastapi-jwt-auth/issues/98#issuecomment-1656652991: I've had good success using https://github.com/k4black/fastapi-jwt as a replacement library. Some changes in the codebase were required, but not much.

avatar-lavventura commented 9 months ago

Is there any update regarding this to issue in order to make it work with pydantic==2..? Is there any alternative or fork for fastapi-jwt-auth ?

amd75692 commented 6 months ago

You will need to change Sequence type to List type in config.py file in the LoadConfig class.

Here is my entire file

from datetime import timedelta
from typing import Optional, Union, Sequence, List
from pydantic import (
    BaseModel,
    validator,
    StrictBool,
    StrictInt,
    StrictStr
)

class LoadConfig(BaseModel):
    authjwt_token_location: Optional[List[StrictStr]] = ['headers']
    authjwt_secret_key: Optional[StrictStr] = None
    authjwt_public_key: Optional[StrictStr] = None
    authjwt_private_key: Optional[StrictStr] = None
    authjwt_algorithm: Optional[StrictStr] = "HS256"
    authjwt_decode_algorithms: Optional[List[StrictStr]] = None
    authjwt_decode_leeway: Optional[Union[StrictInt,timedelta]] = 0
    authjwt_encode_issuer: Optional[StrictStr] = None
    authjwt_decode_issuer: Optional[StrictStr] = None
    authjwt_decode_audience: Optional[Union[StrictStr,Sequence[StrictStr]]] = None
    authjwt_denylist_enabled: Optional[StrictBool] = False
    authjwt_denylist_token_checks: Optional[List[StrictStr]] = ['access','refresh']
    authjwt_header_name: Optional[StrictStr] = "Authorization"
    authjwt_header_type: Optional[StrictStr] = "Bearer"
    authjwt_access_token_expires: Optional[Union[StrictBool,StrictInt,timedelta]] = timedelta(minutes=15)
    authjwt_refresh_token_expires: Optional[Union[StrictBool,StrictInt,timedelta]] = timedelta(days=30)
    # # option for create cookies
    authjwt_access_cookie_key: Optional[StrictStr] = "access_token_cookie"
    authjwt_refresh_cookie_key: Optional[StrictStr] = "refresh_token_cookie"
    authjwt_access_cookie_path: Optional[StrictStr] = "/"
    authjwt_refresh_cookie_path: Optional[StrictStr] = "/"
    authjwt_cookie_max_age: Optional[StrictInt] = None
    authjwt_cookie_domain: Optional[StrictStr] = None
    authjwt_cookie_secure: Optional[StrictBool] = False
    authjwt_cookie_samesite: Optional[StrictStr] = None
    # # option for double submit csrf protection
    authjwt_cookie_csrf_protect: Optional[StrictBool] = True
    authjwt_access_csrf_cookie_key: Optional[StrictStr] = "csrf_access_token"
    authjwt_refresh_csrf_cookie_key: Optional[StrictStr] = "csrf_refresh_token"
    authjwt_access_csrf_cookie_path: Optional[StrictStr] = "/"
    authjwt_refresh_csrf_cookie_path: Optional[StrictStr] = "/"
    authjwt_access_csrf_header_name: Optional[StrictStr] = "X-CSRF-Token"
    authjwt_refresh_csrf_header_name: Optional[StrictStr] = "X-CSRF-Token"
    authjwt_csrf_methods: Optional[List[StrictStr]] = ['POST','PUT','PATCH','DELETE']

    @validator('authjwt_access_token_expires')
    def validate_access_token_expires(cls, v):
        if v is True:
            raise ValueError("The 'authjwt_access_token_expires' only accept value False (bool)")
        return v

    @validator('authjwt_refresh_token_expires')
    def validate_refresh_token_expires(cls, v):
        if v is True:
            raise ValueError("The 'authjwt_refresh_token_expires' only accept value False (bool)")
        return v

    @validator('authjwt_denylist_token_checks', each_item=True)
    def validate_denylist_token_checks(cls, v):
        if v not in ['access','refresh']:
            raise ValueError("The 'authjwt_denylist_token_checks' must be between 'access' or 'refresh'")
        return v

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

    @validator('authjwt_cookie_samesite')
    def validate_cookie_samesite(cls, v):
        if v not in ['strict','lax','none']:
            raise ValueError("The 'authjwt_cookie_samesite' must be between 'strict', 'lax', 'none'")
        return v

    @validator('authjwt_csrf_methods', each_item=True)
    def validate_csrf_methods(cls, v):
        if v.upper() not in ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH"]:
            raise ValueError("The 'authjwt_csrf_methods' must be between http request methods")
        return v.upper()

    class Config:
        str_min_length = 1
        str_strip_whitespace = True
sahilgupta757 commented 5 months ago

Using it from this fork resolved the issue for me. I just bumped the pydantic version to 2.7.0 without any application errors.

jahongir7797 commented 3 months ago

I have problem belong TypeError: @validator(..., each_item=True) cannot be applied to fields with a schema of json-or-python can you help me to solve this problem

sahilgupta757 commented 3 months ago

@jahongir7797 Use the mentioned fork in the above comment. That resolved it for me.