Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to new MSAL auth_code_flow API #55

Merged
merged 2 commits into from
Dec 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,23 @@ def index():

@app.route("/login")
def login():
session["state"] = str(uuid.uuid4())
# Technically we could use empty list [] as scopes to do just sign in,
# here we choose to also collect end user consent upfront
auth_url = _build_auth_url(scopes=app_config.SCOPE, state=session["state"])
return render_template("login.html", auth_url=auth_url, version=msal.__version__)
session["flow"] = _build_auth_code_flow(scopes=app_config.SCOPE)
return render_template("login.html", auth_url=session["flow"]["auth_uri"], version=msal.__version__)

@app.route(app_config.REDIRECT_PATH) # Its absolute URL must match your app's redirect_uri set in AAD
def authorized():
if request.args.get('state') != session.get("state"):
return redirect(url_for("index")) # No-OP. Goes back to Index page
if "error" in request.args: # Authentication/Authorization failure
return render_template("auth_error.html", result=request.args)
if request.args.get('code'):
try:
cache = _load_cache()
result = _build_msal_app(cache=cache).acquire_token_by_authorization_code(
request.args['code'],
scopes=app_config.SCOPE, # Misspelled scope would cause an HTTP 400 error here
redirect_uri=url_for("authorized", _external=True))
result = _build_msal_app(cache=cache).acquire_token_by_auth_code_flow(
session.get("flow", {}), request.args)
if "error" in result:
return render_template("auth_error.html", result=result)
return render_template("error.html", result)
session["user"] = result.get("id_token_claims")
_save_cache(cache)
except ValueError: # Usually caused by CSRF
pass # Simply ignore them

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @rayluo could you explain why this is ok to ignore, and would upgrading the ms-identity-python-samples-common repo to the new scheme help mitigate my issue Azure-Samples/ms-identity-python-samples-common#4 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this particular implementation, ignoring the ValueError here would let the next line run, which is to go back to the index page at a not-yet-signed-in state, rather than an error page. The current approach is our desirable user experience to handle the state mismatch.

return redirect(url_for("index"))

@app.route("/logout")
Expand Down Expand Up @@ -83,10 +78,9 @@ def _build_msal_app(cache=None, authority=None):
app_config.CLIENT_ID, authority=authority or app_config.AUTHORITY,
client_credential=app_config.CLIENT_SECRET, token_cache=cache)

def _build_auth_url(authority=None, scopes=None, state=None):
return _build_msal_app(authority=authority).get_authorization_request_url(
def _build_auth_code_flow(authority=None, scopes=None):
rayluo marked this conversation as resolved.
Show resolved Hide resolved
return _build_msal_app(authority=authority).initiate_auth_code_flow(
scopes or [],
state=state or str(uuid.uuid4()),
redirect_uri=url_for("authorized", _external=True))

def _get_token_from_cache(scope=None):
Expand All @@ -98,7 +92,7 @@ def _get_token_from_cache(scope=None):
_save_cache(cache)
return result

app.jinja_env.globals.update(_build_auth_url=_build_auth_url) # Used in template
app.jinja_env.globals.update(_build_auth_code_flow=_build_auth_code_flow) # Used in template

if __name__ == "__main__":
app.run()
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Flask>=1,<2
werkzeug>=1,<2
flask-session~=0.3.2
requests>=2,<3
msal>=0.6.1,<2
msal>=1.7,<2

# cachelib==0.1 # Only need this if you are running Python 2
# Note: This sample does NOT directly depend on cachelib.
Expand Down
2 changes: 1 addition & 1 deletion templates/auth_error.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

{% if config.get("B2C_RESET_PASSWORD_AUTHORITY") and "AADB2C90118" in result.get("error_description") %}
<!-- See also https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-policies#linking-user-flows -->
<meta http-equiv="refresh" content='0;{{_build_auth_url(authority=config["B2C_RESET_PASSWORD_AUTHORITY"])}}'>
<meta http-equiv="refresh" content='0;{{_build_auth_code_flow(authority=config["B2C_RESET_PASSWORD_AUTHORITY"])["auth_uri"]}}'>
{% endif %}
</head>
<body>
Expand Down
2 changes: 1 addition & 1 deletion templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h2>Welcome {{ user.get("name") }}!</h2>
{% endif %}

{% if config.get("B2C_PROFILE_AUTHORITY") %}
<li><a href='{{_build_auth_url(authority=config["B2C_PROFILE_AUTHORITY"])}}'>Edit Profile</a></li>
<li><a href='{{_build_auth_code_flow(authority=config["B2C_PROFILE_AUTHORITY"])["auth_uri"]}}'>Edit Profile</a></li>
{% endif %}

<li><a href="/logout">Logout</a></li>
Expand Down
2 changes: 1 addition & 1 deletion templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ <h1>Microsoft Identity Python Web App</h1>
<li><a href='{{ auth_url }}'>Sign In</a></li>

{% if config.get("B2C_RESET_PASSWORD_AUTHORITY") %}
<li><a href='{{_build_auth_url(authority=config["B2C_RESET_PASSWORD_AUTHORITY"])}}'>Reset Password</a></li>
<li><a href='{{_build_auth_code_flow(authority=config["B2C_RESET_PASSWORD_AUTHORITY"])["auth_uri"]}}'>Reset Password</a></li>
{% endif %}

<hr>
Expand Down