Flask-OIDC Keycloak HTTPS Redirect on Localhost

590 Views Asked by At

This is the development setup I have. All host references are localhost.

I am using Flask-OIDC 2.0.3 along with Keycloak 22.0.3 (running on Docker as a service). The Flask app runs on port 8080, Keycloak on 9080 and I have a React UI running on port 9001.

All these services are running on http and not https

My Keycloak docker-compose file is as follows

version: '3.8'
name: keycloak
services:
  keycloak:
    image: quay.io/keycloak/keycloak:22.0.3
    command: ['start-dev --import-realm']
    volumes:
      - ./realm-config:/opt/keycloak/data/import
    environment:
      - KC_DB=dev-file
      - KEYCLOAK_ADMIN=admin
      - KEYCLOAK_ADMIN_PASSWORD=admin
      - KC_FEATURES=scripts
      - KC_HTTP_PORT=9080
      - KC_HEALTH_ENABLED=true
      - KC_HTTPS_REQUIRED=false
    # If you want to expose these ports outside your dev PC,
    # remove the "127.0.0.1:" prefix
    ports:
      - 127.0.0.1:9080:9080
      - 127.0.0.1:9443:9443

My client_secrets.json is as follows

{
  "web": {
    "client_id": "<client>",
    "client_secret": "<secret>",
    "auth_uri": "http://127.0.0.1:9080/realms/jhipster/protocol/openid-connect/auth",
    "token_uri": "http://127.0.0.1:9080/realms/jhipster/protocol/openid-connect/token",
    "issuer": "http://127.0.0.1:9080/realms/jhipster",
    "userinfo_uri": "http://127.0.0.1:9080/realms/jhipster/protocol/openid-connect/userinfo",
    "token_introspection_uri": "http://127.0.0.1:9080/realms/jhipster/protocol/openid-connect/token/introspect"
  }
}

I configure my Flask app as follows

OIDC_CLIENT_SECRETS = "src/main/python/config/client_secrets.json"
OIDC_REDIRECT_URI = "http://127.0.0.1:8080/oidc_callback"

My Keycloak client configuration is as follows

Keycloak client Configuration

When I click on the sign-in URL of my UI, it takes me to the Keycloak sign-in page of the new realm I created. But I see that the redirect_uri has been changed to https.

Keycloak sign-in

If I proceed with the login, I get an error Secure Connection Failed

I have tried the following

  • Removed https from the redirect_uri list in Keycloak for the client
    • Then I get an error on the Keycloak sign-in page saying "Invalid redirect_uri"
  • Removed https from the URL in the browser address bar manually and signed-in
    • Then I get an error "invalid_grant: Incorrect redirect_uri"

Actual question:

Part 1: Since this entire setup is running entirely on my local machine, I an not sure where the https redirect is being picked up and how to prevent it? This looks like a Keycloak issue (just a guess) of redirection preference to https but it seems strange since the traffic originates from http.

Part 2: Do I need to explicitly implement /oidc_callback. I assume Flask-OIDC will take care of handling this.

3

There are 3 best solutions below

0
On

This article is mentioned in the github issue Conversion of HTTP URLs to HTTPS in request_uris. A config setting OIDC_OVERWRITE_REDIRECT_URI was added as a part of the fix for the issue.

You can see the relevant code in /flask_oidc/views.py.

My reading of the code is: if you have OIDC_CALLBACK_ROUTE it will get converted to https. You can override by setting OIDC_OVERWRITE_REDIRECT_URI.

This worked for me:

APP.config.update({
    ...
    'OIDC_CALLBACK_ROUTE': '/authorization-code/callback',
    'OIDC_OVERWRITE_REDIRECT_URI': 'http://localhost:5000/authorization-code/callback'
})
0
On

The problem seems to be with Flask-OIDC. The library has a commit that forces redirect URLs to be over HTTPS.

If I change the _scheme to http in line 55, the entire flow works as expected.

enter image description here

0
On

Sudeep Hasra's answer is right.

A workaround would be to use flask's ssl_context option. This way all your app would run over ssl. Two of the most simple options are:

  1. Use ssl_context="adhoc"
  2. Use ssl_context=("/path/to/cert.pem", "/path/tokey.pem")

Example:

if __name__ == "__main__":
    app.run('0.0.0.0', debug=True, ssl_context=("/path/to/cert.pem", "/path/tokey.pem"))

If you go by the second option, you must create the certificate pair. In linux you could do as follows:

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365

Hope it helps you.