Skip to content

Commit d3aec67

Browse files
authored
Merge pull request #9 from NASA-AMMOS/8-implement-pkce-support-for-keycloak
Add PKCE support to oauth2 endpoint for added security when interacting with KeyCloak server
2 parents e95e90c + f9417c1 commit d3aec67

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

flaskProxyWithAuth.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import os
22
from flask import request, jsonify, Response, Flask, redirect, url_for, session, render_template_string, render_template
3+
import secrets
4+
import hashlib
5+
import base64
36
from authlib.integrations.flask_client import OAuth
47
#from dotenv import load_dotenv
58
import 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+
5161
def 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

6280
app = Flask(__name__)
6381
app.secret_key = os.getenv("FLASK_SECRET_KEY")
@@ -91,7 +109,11 @@ def flask_internal_proxy(some_path):
91109
# Auth callback
92110
@app.route("/oauth2")
93111
def 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

Comments
 (0)