kroketio / quart-keycloak

Add Keycloak OpenID Connect support to your Quart application.
BSD 3-Clause "New" or "Revised" License
12 stars 4 forks source link

Missing nonce? #10

Open Danferno opened 1 month ago

Danferno commented 1 month ago

I get following error:

Traceback (most recent call last):
  File "C:\virtualenvs\api-venv\Lib\site-packages\hypercorn\asyncio\task_group.py", line 27, in _handle
    await app(scope, receive, send, sync_spawn, call_soon)
  File "C:\virtualenvs\api-venv\Lib\site-packages\hypercorn\app_wrappers.py", line 34, in __call__
    await self.app(scope, receive, send)
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1667, in __call__
    await self.asgi_app(scope, receive, send)
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1693, in asgi_app
    await asgi_handler(receive, send)
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\asgi.py", line 52, in __call__
    raise_task_exceptions(done)
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\utils.py", line 180, in raise_task_exceptions
    raise task.exception()
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\asgi.py", line 100, in handle_request
    response = await _handle_exception(self.app, error)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\asgi.py", line 357, in _handle_exception
    raise error
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\asgi.py", line 98, in handle_request
    response = await self.app.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1407, in handle_request
    return await self.handle_exception(error)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1403, in handle_request
    return await self.full_dispatch_request(request_context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1441, in full_dispatch_request
    result = await self.handle_user_exception(error)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1029, in handle_user_exception
    raise error
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1439, in full_dispatch_request
    result = await self.dispatch_request(request_context)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart\app.py", line 1535, in dispatch_request
    return await self.ensure_async(handler)(**request_.view_args)  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\virtualenvs\api-venv\Lib\site-packages\quart_keycloak\openid.py", line 353, in auth
    raise Exception(f"Missing nonce in {token}")

When trying to log in with following code:

# Imports
import json, os
import logging

from quart import Quart, redirect, url_for, session
from quart_session import Session
from quart_keycloak import Keycloak, KeycloakAuthToken, KeycloakLogoutRequest

# Logging
logging.basicConfig(level=logging.DEBUG)

# App
app = Quart(__name__)
app.config['SECRET_KEY'] = 'tempkey'
app.config['SESSION_TYPE'] = 'redis'

openid_keycloak_config = {
    "client_id": "testapp",
    "client_secret": "[[redacted]]",
    "configuration": "http://localhost:8080/realms/local/.well-known/openid-configuration"
}
keycloak = Keycloak(app, **openid_keycloak_config)
Session(app)

@keycloak.after_login()
async def handle_user_login(auth_token: KeycloakAuthToken):
    user = await keycloak.user_info(auth_token.access_token)

    session['auth_token'] = auth_token
    return redirect(url_for('index'))

@app.route('/logout')
async def logout():
    session.clear()
    return redirect(url_for('index'))

@app.route('/')
async def index():
    logout_url = url_for('logout', external=True)
    login_url_keycloak = url_for(keycloak.endpoint_name_login)
    logout_url_keycloak = url_for(keycloak.endpoint_name_logout, redirect_uri=logout_url, state='bla')

    return f"""
    <b>token:</b> {session.get('auth_token')}<br><hr>
    Login via keycloak: <a href="{login_url_keycloak}">Login via Keycloak</a><br>
    Logout via keycloak: <a href="{logout_url_keycloak}">Logout via Keycloak</a>
    """

if __name__ == '__main__':
    app.run(port=5000, debug=True)

using versions Keycloak: 25.0.1 Quart: 0.19.6 Quart-Keycloak: 1.0.8

Danferno commented 1 month ago

Of course, after trying to fix it for hours, right after I post the issue I find the solution. Keycloak no longer adds nonces and you have to manually add the Nonce backwards compatible mapper to make it work with Quart-Keycloak.