lepture / authlib

The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.
https://authlib.org/
BSD 3-Clause "New" or "Revised" License
4.49k stars 448 forks source link

Allow `authorize_redirect` to save user defined state data #521

Closed n0061q closed 1 year ago

n0061q commented 1 year ago

Is your feature request related to a problem? Please describe. I am using Flask OAuth Client (https://docs.authlib.org/en/latest/client/flask.html#routes-for-authorization) However there seem to be no proper way save user defined data to the state with authorize_redirect (and to extract in the authorize route before calling authorize_access_token). This is crutial for such use cases when client needs to redirect user to the original resourse after successfull authentication (e.g. see this)

It can be worked aroud as described below but it is a bit hackish.

Describe the solution you'd like

It would be nice if authorize_redirect could accept user defined data to save in the state and some method that could get this custom data from the state later while handling the /authorize request.

Describe alternatives you've considered

Workaround (Flask)

@app.route("/login")
def login():
    redirect_uri = url_for(".authorize", _external=True)
    # return oauth.provider.authorize_redirect(redirect_uri)

    # I want to save referer URL to the state data
    # https://github.com/lepture/authlib/blob/4bdc72415a69e2f7c8993dd8375258be4036af1e/authlib/integrations/flask_client/apps.py#L36-L45
    rv = oauth.provider.create_authorization_url(redirect_uri)
    rv.update(referer_url=request.headers.get("Referer"))
    oauth.provider.save_authorize_data(redirect_uri=redirect_uri, **rv)
    return redirect(rv["url"])

@app.route("/authorize")
def authorize():
    # here I retrieve state data from session to get the referer URL
    state_data = oauth.provider.framework.get_state_data(session, request.args.get("state"))
    # state is cleared by calling authorize_access_token
    token = oauth.provider.authorize_access_token()
    # ...
    return redirect(state_data.get("referer_url", url_for(".index")))

Additional context

lepture commented 1 year ago

@n0061q I think you may not understand what you want, from your description, the referrer url is not a part of the oauth flow, it is your application's logic requirements. In this case, you can just save the referrer url in your session:

    next_url = request.headers.get("Referer")
    if next_url:
        session['next_url'] = next_url
    return oauth.provider.authorize_redirect(redirect_uri)

Then:

next_url = session.get('next_url', url_for(".index"))
return redirect(next_url)