11import os
22from flask import request , jsonify , Response , Flask , redirect , url_for , session , render_template_string , render_template
3+ import secrets
4+ import hashlib
5+ import base64
36from authlib .integrations .flask_client import OAuth
47#from dotenv import load_dotenv
58import requests
@@ -48,6 +51,13 @@ def is_token_expired(token):
4851 return True
4952 return token ['expires_at' ] < time ()
5053
54+ def generate_pkce_pair ():
55+ code_verifier = base64 .urlsafe_b64encode (secrets .token_bytes (32 )).rstrip (b'=' ).decode ('utf-8' )
56+ code_challenge = base64 .urlsafe_b64encode (
57+ hashlib .sha256 (code_verifier .encode ('utf-8' )).digest ()
58+ ).rstrip (b'=' ).decode ('utf-8' )
59+ return code_verifier , code_challenge
60+
5161def check_user_session_then_proxy (target_url = "http://localhost:80" ):
5262 user = session .get ("user" )
5363 token = session .get ("token" )
@@ -56,8 +66,16 @@ def check_user_session_then_proxy(target_url="http://localhost:80"):
5666 else :
5767 session .pop ("user" , None )
5868 session .pop ("token" , None )
69+ # PKCE: generate code_verifier and code_challenge
70+ code_verifier , code_challenge = generate_pkce_pair ()
71+ session ["pkce_code_verifier" ] = code_verifier
5972 redirect_uri = url_for ("oauth2" , _external = True )
60- return oauth .keycloak .authorize_redirect (redirect_uri )
73+ # Pass PKCE params to authorize_redirect
74+ return oauth .keycloak .authorize_redirect (
75+ redirect_uri ,
76+ code_challenge = code_challenge ,
77+ code_challenge_method = "S256"
78+ )
6179
6280app = Flask (__name__ )
6381app .secret_key = os .getenv ("FLASK_SECRET_KEY" )
@@ -91,7 +109,11 @@ def flask_internal_proxy(some_path):
91109# Auth callback
92110@app .route ("/oauth2" )
93111def oauth2 ():
94- token = oauth .keycloak .authorize_access_token ()
112+ # PKCE: pass code_verifier when fetching token
113+ code_verifier = session .pop ("pkce_code_verifier" , None )
114+ token = oauth .keycloak .authorize_access_token (
115+ code_verifier = code_verifier
116+ )
95117 session ["user" ] = oauth .keycloak .parse_id_token (token , None )
96118 session ["token" ] = token
97119 return redirect ("/" )
0 commit comments