singingwolfboy / flask-dance

Doing the OAuth dance with style using Flask, requests, and oauthlib.
https://pypi.python.org/pypi/Flask-Dance/
MIT License
1.01k stars 158 forks source link

Customizing the token_url and authorization_url based on the request #279

Open jtmoulia opened 5 years ago

jtmoulia commented 5 years ago

I'm working with an OAuth2 interface where I need to customize the token_url and authorization_url based on parameters passed in the initial OAuth authentication request itself, i.e. I don't know those vars until an OAuth dance has been initiated by the user.

As far as I can tell, with flask-dance's model of defining the OAuth blueprint up-front, the authorization_url and token_url can't be customized. Am I correct?

If there isn't yet a way to customize those variables, how could flask-dance be patched to allow it? Could token_url and authorization_url allow callback functions that return the correct URL for that user's OAuth flow?

Other than this issue, the flask-dance been working great for me and the code is quite readable. Thanks!

daenney commented 5 years ago

This seems a little peculiar. Can you explain a bit how your flows work, i.e how come you don't know the endpoints before the flow gets initiated?

jtmoulia commented 5 years ago

Yup, it's definitely different -- it's how Cerner (a major US electronic health record company) designed their SMART on FHIR interface, which includes OAuth.

The workflow uses the tenant ID provided by the OAuth authentication request to fetch the token and authorization URLs, as described here. In Cerner's system a hospital/provider can have multiple tenants, each of which "owns" a subset of the users. I don't know which tenant a user belongs to until I get the initial authorization OAuth request.

I agree it's peculiar, but it's looking like something that's necessary for interfacing with electronic health records over SMART on FHIR. Given that SMART on FHIR satisfies the US meaningful use interoperability requirements and is now supported by the top US EHRs (Epic & Cerner, by market share) it isn't a unique use-case.

Thanks for the reply @daenney !

singingwolfboy commented 5 years ago

@jtmoulia Interesting situation! This is not something that I planned for when writing Flask-Dance, so no, the code does not explicitly support it.

However, you might be able to hack it in somehow. The first idea that I have is based on the fact that Flask-Dance is built on Flask blueprints, so you can use all the standard functionality of any other blueprint -- including before_request handlers. The token_url and authorization_url are set in the constructor as properties on the blueprint itself, so you could simply overwrite those properties in a before_request handler with the values that you want.

If you want to do this in a less-hacky way, it might require rethinking some of the assumptions of this library, and potentially rearchitecting parts of it. If you want to do that, then maybe you and I can hop on a videocall sometime and discuss it, and then you can send a pull request that I can review and merge in.

Man, people implement OAuth in all sorts of unusual ways!

jtmoulia commented 5 years ago

Thanks for the detailed respond @singingwolfboy !

I'll start out with the hack, but I'd love to understand how it could be implemented appropriately. You can get ahold of me over email at thomas at healthtensor.com (and, the offer is much appreciated)

Man, people implement OAuth in all sorts of unusual ways!

:)

vincentjr commented 5 years ago

+1 on this. Running into the issue building a provider for Shopify, where 'shop' is required in the url.

https://{shop}.myshopify.com/admin/oauth/authorize?client_id={api_key}&scope={scopes}&redirect_uri={redirect_uri}&state={nonce}&grant_options[]={access_mode}