Search code examples
flaskkeycloakgitpodflask-oidc

Keycloak Gitpod Flask OIDC: oauth2client.client.FlowExchangeError: Invalid response: 301


I'm trying to implement Flask-OIDC and Keycloak in a Flask app run inside a Gitpod workspace.

I'm running the application and the Keycloak server like this:

./keycloak-11.0.3/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 &
flask run --host=0.0.0.0 & 

Based on this post

I'm able to redirect to the Keycloak login page for regular users from within the Flask application, but when I login with an existing user I get the following:

oauth2client.client.FlowExchangeError: Invalid response: 301


My client_secrets.json currently looks something like this:

{
  "web": {
    "auth_uri": "http://keycloak-hostname-gitpod/auth/realms/realm/protocol/openid-connect/auth",
    "issuer": "http://keycloak-hostname-gitpod/auth/realms/realm",
    "userinfo_uri": "http://keycloak-hostname-gitpod/auth/realms/realm/protocol/openid-connect/userinfo",
    "client_id": "client",
    "client_secret": "client_secret",
    "redirect_uris": ["http://flask-app-hostname-gitpod/oidc_callback"],
    "token_uri": "http://keycloak-hostname-gitpod/auth/realms/realm/protocol/openid-connect/token",
    "token_introspection_uri": "http://keycloak-hostname-gitpod/auth/realms/realm/openid-connect/token/introspect"
  }
}

Relevant client configuration inside keycloak:

Root URL:            http://flask-app-hostname-gitpod/*
Valid Redirect URIs: http://flask-app-hostname-gitpod/*
Admin URL:           http://flask-app-hostname-gitpod/*
Web Origins:         http://flask-app-hostname-gitpod

I use http in all of these urls instead of https, because when I use https Keycloak says the redirect_uri is invalid. This seems to be the actual problem here since the gitpod urls use https, but I'm not sure how to handle this. I've tried some solutions like described here, but couldn't get them to work.

Relevant part routing:

@app.route("/")
def hello_world():
    if oidc.user_loggedin:
        return (
            'Hello, %s, <a href="/private">See private</a> '
            '<a href="/logout">Log out</a>'
        ) % oidc.user_getfield("preferred_username")
    else:
        return 'Welcome anonymous, <a href="/private">Log in</a>'


@app.route("/private")
@oidc.require_login
def test():
    return "test"

Parts of standalone.xml that might be relevant:

<http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true" read-timeout="30000" proxy-address-forwarding="true" />
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true" read-timeout="30000" />

Update

After following changing the http urls to https as Jan Garaj suggested and setting the OVERWRITE_REDIRECT_URI I don't get the invalid response: 301 error anymore:

OVERWRITE_REDIRECT_URI = "https://flask-app-hostname-gitpod/oidc_callback"

Now I'm able to go to the keycloak login form, but on logging in I now get:

oauth2client.client.FlowExchangeError: Invalid response: 401.

These are the requests made:

https://keycloak-hostname-gitpod/auth/realms/realm/login-actions/authenticate?session_code=session_code&execution=execution&client_id=client&tab_id=tab_id
https://flask-app-hostname-gitpod/oidc_callback?state=state&session_state=session_state&code=code

Requests inside the network inspector: requests network


Solution

  • After much trial end error I've finally figured out what the problem was.

    The redirect problem in the original question was solved by setting OVERWRITE_REDIRECT_URI:

    OVERWRITE_REDIRECT_URI = "https://flask-app-hostname-gitpod/oidc_callback"
    

    The oidc_callback request was still not working however, I was getting this:

    oauth2client.client.FlowExchangeError: Invalid response: 401.

    Jan Garaj's comment made me realise the problem was that the token endpoint request was not working.

    I had checked the token endpoint uri multiple times and copied the value from:

    https://flask-app-hostname-gitpod/auth/realms/demo/.well-known/openid-configuration
    

    but it still didn't work.

    The reason it didn't work was actually unrelated to my Keycloak configuration, but the way my keycloak server was running inside Gitpod.

    Gitpod set the port that the keycloak server was running on to private. Because the keycloak server was running on a private port, the request to the follwing url failed:

    https://keycloak-hostname-gitpod/auth/realms/demo/protocol/openid-connect/token
    

    After making the port public it worked.

    ports

    if you already know that you want a particular port exposed, you can configure it in .gitpod.yml:

    ports:
      - port: 5000
        onOpen: open-preview
      - port: 8080
    

    https://www.gitpod.io/docs/config-ports