code-specialist / fastapi-keycloak

Keycloak integration for Python FastAPI
https://fastapi-keycloak.code-specialist.com/
Apache License 2.0
192 stars 49 forks source link

realmRoles Field required #101

Open ricciarellif opened 1 year ago

ricciarellif commented 1 year ago

Using the examples provided, I'm unable to get the user's info through the route

http://localhost:8081/user/2b1b34f0-5efb-4cf8-b620-b619fd9b98bc (it's a valid user-id)

due to a pydantic error:

pydantic_core._pydantic_core.ValidationError: 1 validation error for KeycloakUser realmRoles Field required [type=missing, input_value={'id': '2b1b34f0-5efb-4cf8-b620-b619fd9b98bc'...}, input_type=dict] For further information visit https://errors.pydantic.dev/2.1/v/missing

This is due to the absence, in the incoming json (Python dict), of the key "realmRoles" which is NOT always returned by the KeyCloak platform.

In your model.py module, class KeycloakUser(BaseModel), the realmRoles field is specified as "Optional" (realmRoles: Optional[List[str]]) but this attribute seems to be ignored by pydantic...

Any suggestion? Thanks in advance

My requirements.txt: fastapi==0.100.1 fastapi_keycloak==1.0.10 pydantic==2.2.1 uvicorn==0.23.1

My KeyCloack platform: docker image of jsboss/keycloak:latest (Server version: 16.1.1) with postgresql 13.0

softfactory1 commented 1 year ago

Hi, you can apply a workaround as a patch of KeycloakUser.__init__ like the following:

    oryg__init__ = KeycloakUser.__init__

    def mocked__init__(*args, **kwargs):
        kwargs['realmRoles'] = kwargs.get('realmRoles', [])
        kwargs['attributes'] = kwargs.get('attributes', {})
        oryg__init__(*args, **kwargs)

    KeycloakUser.__init__ = mocked__init__
praveenexaf commented 11 months ago

In which file we have to apply this?

softfactory1 commented 11 months ago

You can define it in any file like the following function

def patcher():
    from fastapi_keycloak import KeycloakUser

    oryg__init__ = KeycloakUser.__init__

    def new__init__(*args, **kwargs):
        kwargs['realmRoles'] = kwargs.get('realmRoles', [])
        kwargs['attributes'] = kwargs.get('attributes', {})
        oryg__init__(*args, **kwargs)

    KeycloakUser.__init__ = new__init__

And call patcher before any fast API code is executed in some main.py or whatever the main module you defined.

alexbarcelo commented 8 months ago

I believe that this is related to #97. But it has been a while, so maybe I misremember the error I got at that point.