zmartzone / lua-resty-openidc

OpenID Connect Relying Party and OAuth 2.0 Resource Server implementation in Lua for NGINX / OpenResty
Apache License 2.0
976 stars 249 forks source link

Handling session refresh in flask app with Azure AD leads to 405 on form submission #511

Open sasharozenson opened 8 months ago

sasharozenson commented 8 months ago

Environment:

lua-resty-openidc version: 1.7.6-3
OpenID Connect provider: Azure AD

Hello everyone,

I've run into a snag with session management while working on a web page that uses a straightforward HTML form with just a bit of JavaScript for sending a POST request. All the backend stuff is handled by a Python Flask app. Here's the pickle: if the page stays open past the refresh_session_interval, and then the user submits the form, we end up getting redirected to Azure (via a GET request), only to bounce right back to the Flask-rendered page, also with a GET request. This leads to a 405 error since the original POST info gets lost in translation.

I'm well aware this might be Web Dev 101 for many of you, but I'm more at home in other areas, so this has been a bit of a real head-scratcher for me.

I've tried a couple of workarounds, like using an iframe and making xhr requests, but Azure isn't having any of it. I'm thinking there's got to be a way to check if we need a session refresh before the form goes off, but I'm stumped on how to make that happen.

Could anyone suggest or give an example code on how to address this situation?

Thank you

sasharozenson commented 8 months ago

I think I've managed to come up with a workaround by configuring an additional /auth location in nginx, which has a shorter refresh_session_interval.

This endpoint is configured in my flask app to redirect users back to their original page after refreshing their session. Additionally, I've implemented a small JS function that redirects to /auth after a period of user inactivity - 15mins.

I'm not entirely sure if this approach is ideal, so I'm keen to get your thoughts. Do you see any potential issues with this method, or do you have any suggestions for handling session refreshes more effectively?

bodewig commented 8 months ago

I don't think there is "the way to do it".

If your token expires there are two ways to refresh them in OpenID Connect. One way is to simply start the redirect based flow all over inside the browser, the other is to obtain a refresh token together with the first token and use that to obtain a new token in a backend to backend call that doesn't involve the browser at all. The redirect based approach really only works for GET requests and in general only works for requests that are a top level navigation and expect an HTML page back as if all things fail the OpenID Connect provider might show the login page. So my general advice is to avoid a browser based refresh and always use a refresh token if possible.

Depending on your OpenID Connect provider it may be necessary to ask for additional scopes in order to obtain a refresh token. offline_access is a common scope name, YMMV. And then you must set renew_access_token_on_expiry to true - which is the default, so you may already be doing it. If you think lua-resty-openidc has a refresh token you could use then the logs may show why it is not using it. For example it may have expired already in which case you'd need to tweak refresh_session_interval or access_token_expires_leeway. Another reason could be that you've explicitly configured lua-resty-openidc to not store the access_token (and thus also not store the refresh_token) inside the session.

sasharozenson commented 8 months ago

Thank you! I've increased the refresh_session_interval and configured offline_access as suggested. After several rounds of testing, I have adapted it to our needs.