Last active
June 2, 2023 20:15
-
-
Save gchamon/0c8632bfd32aea9a6a5a558f823e7a24 to your computer and use it in GitHub Desktop.
Gists with functional code from papyrus article about OIDC, JWT and Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from flask import Flask | |
from uuid import uuid4 | |
app = Flask(__name__) | |
app.config["SECRET_KEY"] = str(uuid4()) | |
IDP_CONFIG = { | |
"well_known_url": "Identity Provider wellknown url: https://{TENANT}.auth0.com/.well-known/openid-configuration", | |
"client_id": "Your app client ID", | |
"client_secret": "Your app client secret", | |
"scope": ["profile", "email", "openid"] | |
} | |
import requests | |
from flask import url_for | |
from requests_oauthlib import OAuth2Session | |
def get_well_known_metadata(): | |
response = requests.get(IDP_CONFIG["well_known_url"]) | |
response.raise_for_status() | |
return response.json() | |
def get_oauth2_session(**kwargs): | |
oauth2_session = OAuth2Session(IDP_CONFIG["client_id"], | |
scope=IDP_CONFIG["scope"], | |
redirect_uri=url_for(".callback", _external=True), | |
**kwargs) | |
return oauth2_session | |
from flask import redirect, session | |
@app.route("/login") | |
def login(): | |
well_known_metadata = get_well_known_metadata() | |
oauth2_session = get_oauth2_session() | |
authorization_url, state = oauth2_session.authorization_url(well_known_metadata["authorization_endpoint"]) | |
session["oauth_state"] = state | |
return redirect(authorization_url) | |
from flask import request | |
@app.route("/callback") | |
def callback(): | |
well_known_metadata = get_well_known_metadata() | |
oauth2_session = get_oauth2_session(state=session["oauth_state"]) | |
session["oauth_token"] = oauth2_session.fetch_token(well_known_metadata["token_endpoint"], | |
client_secret=IDP_CONFIG["client_secret"], | |
code=request.args["code"])["id_token"] | |
return "ok" | |
@app.route("/user/token") | |
def get_user_token(): | |
return session["oauth_token"] | |
import jwt | |
from jwt import PyJWKClient | |
from jwt.exceptions import DecodeError | |
from werkzeug.exceptions import InternalServerError, Unauthorized | |
def get_jwks_client(): | |
well_known_metadata = get_well_known_metadata() | |
jwks_client = PyJWKClient(well_known_metadata["jwks_uri"]) | |
return jwks_client | |
jwks_client = get_jwks_client() | |
@app.before_request | |
def verify_and_decode_token(): | |
if request.endpoint not in {"login", "callback"}: | |
if "Authorization" in request.headers: | |
token = request.headers["Authorization"].split()[1] | |
elif "oauth_token" in session: | |
token = session["oauth_token"] | |
else: | |
return Unauthorized("Missing authorization token") | |
try: | |
signing_key = jwks_client.get_signing_key_from_jwt(token) | |
header_data = jwt.get_unverified_header(token) | |
request.user_data = jwt.decode(token, | |
signing_key.key, | |
algorithms=[header_data['alg']], | |
audience=IDP_CONFIG["client_id"]) | |
except DecodeError: | |
return Unauthorized("Authorization token is invalid") | |
except Exception: | |
return InternalServerError("Error authenticating client") | |
@app.route("/user/id") | |
def get_user_id(): | |
return request.user_data["email"] | |
if __name__ == "__main__": | |
app.run() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from selenium import webdriver | |
from selenium.webdriver.chrome.options import Options as ChromeOptions | |
from selenium.webdriver.common.by import By | |
from selenium.webdriver.support import expected_conditions as EC | |
from selenium.webdriver.support.ui import WebDriverWait | |
chrome_options = ChromeOptions() | |
chrome_options.add_argument("--user-data-dir=chrome-data") | |
chrome_options.add_argument("--app=http://localhost:5000/login") | |
driver = webdriver.Chrome(options=chrome_options) | |
WebDriverWait(driver, 300).until( | |
EC.visibility_of_element_located((By.XPATH, "//*[contains(text(), 'ok')]"))) | |
chromium_cookies = driver.get_cookies() | |
driver.close() | |
requests_cookies = {c["name"]: c["value"] for c in chromium_cookies} | |
import requests | |
token_response = requests.get("http://localhost:5000/user/token", cookies=requests_cookies) | |
token_response.raise_for_status() | |
token = token_response.text | |
userid_response = requests.get("http://localhost:5000/user/id", headers={"Authorization": f"Bearer {token}"}) | |
userid_response.raise_for_status() | |
print(userid_response.text) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
flask==2.0.2 | |
requests-oauthlib==1.3.0 | |
requests==2.26.0 | |
pyjwt[crypto]==2.3.0 | |
selenium==4.1.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment