I'm struggling with securing a flask API backend with flask-oidc and keycloak. My project consist of a React front end and a flask application as REST API protected by a Keycloak server v13.0.1. So I created a public client for the front end and a bearer only client for the backen but I keep getting 401 with a "Token required but invalid message". Flask is not writing any log about the cause of the error. I can't figure out what I'm doing wrong so i hope you are able to help me out.
This is the client_secrets.json for flask-oidc
{
"web": {
"issuer": "http://127.0.0.1:8080/auth/realms/reamar",
"auth_uri": "http://127.0.0.1:8080/auth/realms/reamar/protocol/openid-connect/auth",
"client_id": "reamar-api",
"client_secret": "5d241a3c-d0a2-4811-b54c-d910a8e6aa7e",
"redirect_uris": ["http://127.0.0.1:5000/*"],
"userinfo_uri": "http://127.0.0.1:8080/auth/realms/reamar/protocol/openid-connect/userinfo",
"token_uri": "http://127.0.0.1:8080/auth/realms/reamar/protocol/openid-connect/token",
"token_introspection_uri": "http://127.0.0.1:8080/auth/realms/reamar/protocol/openid-connect/token/instrospect",
"bearer_only": "true"
}
}
These are the flask-oidc config parameters (it's taking always the default values)
OIDC_CLIENT_SECRETS = os.getenv("ODIC_CLIENT_SECRETS", "data/client_secrets.json")
OIDC_COOKIE_SECURE = os.getenv("OIDC_COOKIE_SECURE", False)
OIDC_ID_TOKEN_COOKIE_SECURE = os.getenv("OIDC_ID_TOKEN_COOKIE_NAME", False)
OIDC_SCOPES = os.getenv("OIDC_SCOPES", ["openid", "email", "profile"])
OIDC_USER_INFO_ENABLED = os.getenv("OIDC_USER_INFO_ENABLED", True)
OIDC_OPENID_REALM = os.getenv("OIDC_OPENID_REALM", "reamar")
OIDC_INTROSPECTION_AUTH_METHOD = os.getenv("OIDC_INTROSPECTION_AUTH_METHOD", "client_secret_post")
OIDC_RESOURCE_SERVER_ONLY = os.getenv("OIDC_RESOURCE_SERVER_ONLY", True)
OIDC_RESOURCE_CHECK_AUD = os.getenv("OIDC_RESOURCE_CHECK_AUD", False)
OIDC_REQUIRE_VERIFIED_EMAIL = os.getenv("OIDC_REQUIRE_VERIFIED_EMAIL", False)
OIDC_TOKEN_TYPE_HINT = "access_token"
This is the token protected method:
@TramiteEndpoint.route("/<string:numero>/", methods=["PUT"])
@content_type("application/json")
@accepts("application/json")
@OIDC.accept_token(require_token=True)
def actualizar(numero: str):
tramite = TTramite(unknown=INCLUDE, context={"tramite": numero}).load(
request.get_json()
)
if tramite.estado not in [
EEstadoTramite.INICIADO,
EEstadoTramite.PENDIENTE,
EEstadoTramite.FINALIZADO,
]:
raise Conflict(
"No se puede modificar un trĂ¡mite en estado {}".format(tramite.estado)
)
tipo = tramite.tipo
if tipo == ETipoTramite.DJG:
tramite = TDeclaracionJuradaGeneral(context={"tramite": numero}).load(
request.get_json()
)
elif tipo == ETipoTramite.DJE:
tramite = TDeclaracionJuradaEmpadronamiento(context={"tramite": numero}).load(
request.get_json()
)
elif tipo == ETipoTramite.DJA:
tramite = TDeclaracionJuradaActividad(context={"tramite": numero}).load(
request.get_json()
)
elif tipo == ETipoTramite.DJEELL:
tramite = TDeclaracionJuradaEfluentesLiquidos(context={"tramite": numero}).load(
request.get_json()
)
elif tipo == ETipoTramite.DJRR:
tramite = TDeclaracionJuradaResiduos(context={"tramite": numero}).load(
request.get_json()
)
elif tipo == ETipoTramite.DJEEGG:
tramite = TDeclaracionJuradaEmisionesGaseosas(context={"tramite": numero}).load(
request.get_json()
)
tramite = TramiteRepository(current_app.entityManager).load(tramite)
TramiteRepository(current_app.entityManager).guardar(tramite)
return "", HTTPStatus.NO_CONTENT
And finally this is my keycloak configuration for the client: