Package: sag-py-auth
sag_py_authThis provides a way to secure your fastapi with keycloak jwt bearer authentication.What it doesSecure your api endpointsVerifies auth tokens: signature, expiration, issuer, audienceAllows to set permissions by specifying roles and realm rolesHow to useInstallationpip install sag-py-authSecure your apisFirst create the fast api dependency with the auth config:fromsag_py_auth.modelsimportAuthConfig,TokenRolefromsag_py_auth.jwt_authimportJwtAuthfromfastapiimportDependsauth_config=AuthConfig("https://authserver.com/auth/realms/projectName","myaudience")required_roles=[TokenRole("clientname","adminrole")]required_realm_roles=["additionalrealmrole"]requires_admin=Depends(JwtAuth(auth_config,required_roles,required_realm_roles))Afterwards you can use it in your route like that:@app.post("/posts",dependencies=[requires_admin],tags=["posts"])asyncdefadd_post(post:PostSchema)->dict:Or if you use sub routes, auth can also be enforced for the entire route like that:router=APIRouter()router.include_router(sub_router,tags=["my_api_tag"],prefix="/subroute",dependencies=[requires_admin])Get user informationThe Jwt call directly returns a token object that can be used to get additional information.Furthermore you can access the context directly:fromsag_py_auth.auth_contextimportget_tokenasget_token_from_contexttoken=get_token_from_context()This works in async calls but not in sub threads (without additional changes).See:https://docs.python.org/3/library/contextvars.htmlhttps://kobybass.medium.com/python-contextvars-and-multithreading-faa33dbe953dMethods available on the token objectget_field_value: to get the value of a claim field (or an empty string if not present)get_roles: Gets the roles of a specific clienthas_role: Verify if a spcific client has a roleget_realm_roles: Get the realm roleshas_realm_role: Check if the user has a specific realm roleLog user dataIt is possible to log the preferred_username and the azp value (party that created the token) of the token by adding a filter.importloggingfromsag_py_authimportUserNameLoggingFilterconsole_handler=logging.StreamHandler(sys.stdout)console_handler.addFilter(UserNameLoggingFilter())The filter provides the following two fields as soon as the user is authenticated: user_name, authorized_partyHow a token has to look like{"iss":"https://authserver.com/auth/realms/projectName","aud":["audienceOne","audienceTwo"],"typ":"Bearer","azp":"public-project-swagger","preferred_username":"preferredUsernameValue",....."realm_access":{"roles":["myRealmRoleOne"]},"resource_access":{"my-client-one":{"roles":["a-permission-role","user"]},"my-client-two":{"roles":["a-permission-role","admin"]}}}realm_access contains the realm rolesresource_access contains the token roles for one or multiple clientsHow to start developingWith vscodeJust install vscode with dev containers extension. All required extensions and configurations are prepared automatically.With pycharmInstall latest pycharmInstall pycharm plugin BlackConnectInstall pycharm plugin MypyConfigure the python interpreter/venvpip install requirements-dev.txtpip install black[d]Ctl+Alt+S => Check Tools => BlackConnect => Trigger when saving changed filesCtl+Alt+S => Check Tools => BlackConnect => Trigger on code reformatCtl+Alt+S => Click Tools => BlackConnect => "Load from pyproject.yaml" (ensure line length is 120)Ctl+Alt+S => Click Tools => BlackConnect => Configure path to the blackd.exe at the "local instance" config (e.g. C:\Python310\Scripts\blackd.exe)Ctl+Alt+S => Click Tools => Actions on save => Reformat codeRestart pycharmHow to publishUpdate the version in setup.py and commit your changeCreate a tag with the same version numberLet github do the rest