What you want to do is as the title says, so you can skip the introduction.
I was writing an app to play with Google Calendar using the Google API Client Library. Drop the OAuth2 client information from Google Cloud Platform as client_secret.json
and specify the ** file name ** in the argument of ʻoauth2client.client.flow_from_clientsecrets ()`.
The problem here. I don't want to add client_secret.json
to git version control due to security concerns. However, I'm running the app on Heroku, so I can't upload files. (It seems that you should use object storage such as Amazon S3, but I stopped it because it is annoying because I have never used it)
So I had to specify client_secret.json
, but I was having trouble putting that file on the Heroku server.
So, I want to put dictionary type data in ʻoauth2client.client.flow_from_clientsecrets () function instead of
file name. Then, store the contents of
client_secret.json` in the environment variables of Heroku and put them in the dictionary data.
(Is it really bad to put confidential information in environment variables?)
After writing the code, I realized that I should have created an instance of ʻOAuth2WebServerFlow` normally. Therefore, it is not necessary to override it separately, but I will leave it because I learned that it can be overridden in this way.
ʻOauth2client.client.flow_from_clientsecrets ()` I want the function to contain ** dictionary type ** instead of ** filename **.
The source code of the library looked like this. (The following is an excerpt from the Apache license code of Google Inc.)
Partially omitted from ʻoauth2client.client.py`.
@_helpers.positional(2)
def flow_from_clientsecrets(filename, scope, redirect_uri=None,
message=None, cache=None, login_hint=None,
device_uri=None, pkce=None, code_verifier=None):
try:
client_type, client_info = clientsecrets.loadfile(filename,
cache=cache)
if client_type in (clientsecrets.TYPE_WEB,
-----The following is omitted------
Note that filename
is passed toclientsecrets.loadfile ()
.
I also looked at clientsecrets.loadfile ()
.
def loadfile(filename, cache=None):
_SECRET_NAMESPACE = 'oauth2client:secrets#ns'
if not cache:
return _loadfile(filename)
obj = cache.get(filename, namespace=_SECRET_NAMESPACE)
-----The following is omitted------
If cache
does not exist, the processing is transferred to the _loadfile
function. Let's take a look at _loadfile
.
def _loadfile(filename):
try:
with open(filename, 'r') as fp:
obj = json.load(fp)
except IOError as exc:
raise InvalidClientSecretsError('Error opening file', exc.filename,
exc.strerror, exc.errno)
return _validate_clientsecrets(obj)
I arrived at the function that is loading the file. If you override this function, you might put a dictionary type in the filename
argument.
So after that my code
# `client.flow_from_clientsecrets`Functions can take dictionary type as arguments
# `clientsecrets._loadfile`Override function
def new_loadfile(data):
return clientsecrets._validate_clientsecrets(data)
clientsecrets._loadfile = new_loadfile
After this
flow = client.flow_from_clientsecrets(
Dictionary type,
scope='https://www.googleapis.com/auth/calendar',
redirect_uri=flask.url_for('oauth2callback', _external=True))
You can now use flow_from_clientsecrets
, which takes a dictionary type as an argument.
def new_func(args):
#Various processing
return hoge
hoge_library.func = new_func
This way it's easy to override and it affects all the functions that use that function.
Overriding library functions I did it for the first time, but it works so easily. I'm scared.
Recommended Posts