What I’m trying to do:
I am trying to build an application that will be able to generate reports based on data in the database. Reports are json files that are to be placed on a google drive through a process run from anvil.works scheduled tasks.
What I’ve tried and what’s not working:
I am having problem wiith authenticating to Google API via OAuth2 - because the backend process is unable to perform the user login operation.
It seems that the most suitable flow based on google service accounts, which is recommended for server-server communication. Unfortunately, it uses the library
from google.oauth2 import service_account
Has anyone encountered a similar problem?
Hi @aleksander.stanik
This is a good question, and the Google API documentation is rather unhelpful! You’re right that a service account is the way to go. When I built something similar recently, here’s how I did it:
-
Create a new project at https://console.cloud.google.com/
-
Create a Service Account for the project from the Credentials screen
-
Generate a new Key for the Service Account, and choose the JSON format. Store the JSON key as an App Secret service_account_key
in your Anvil app
-
Load the key in your server code to generate a Credentials object:
from google.oauth2.service_account import Credentials
key = json.loads(anvil.secrets.get_secret('service_account_key'))
creds = Credentials.from_service_account_info(key)
-
Use the credentials object with the Google API libraries. My app used PubSub, so looked like this:
from google.cloud import pubsub_v1
client = pubsub_v1.PublisherClient(credentials=creds)
...
I’m sure there will be an equivalent for Google Drive.
I hope this helps. I have also written equivalent code that uses OAuth credentials from particular users which I would be happy to share if it would be useful.
–
I found the following links helpful when working out how to do this:
Source code: Service Account Credentials
Source code: OAuth Credentials
N.B. If any future readers are unable to import the Google API libraries in their Full Python 3 server environment, please send an email to support@anvil.works and we’ll make sure those are made available for you, as I have now done for @aleksander.stanik.
5 Likes
Hi @daviesian
Thank you, you saved me a lot of time.
Below is an example implementation with a short description in case someone was struggling with a similar problem.
ATTENTION! Remember to share, for example, your local google drive directory with the mailing address of the service account, otherwise your data will be loaded into the local storage of the assigned service account that cannot be directly accessed.
from google.oauth2.service_account import Credentials
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseUpload
import json
from io import StringIO
@anvil.server.callable
def test_upload():
key = json.loads(anvil.secrets.get_secret('service_account_key'))
creds = Credentials.from_service_account_info(key)
service = build('drive', 'v3', credentials=creds)
file_name = "test_file.json"
folder_id = "1U5m8s...............Dg"
#File metadata (file setup)
file_metadata = {
'name': file_name,
'parents': [folder_id]
}
#JSON file payload
json_data = {
"ANVIL" : "WORKS"
}
#Convert json_data payload to "in-memory file-like object"
data = StringIO(json.dumps(json_data))
# Generate media upload object
media = MediaIoBaseUpload(data, mimetype="text/json")
#Create file on google drive with json payload
cloudFile = service.files().create(body=file_metadata, media_body=media).execute()
Best,
Olek
2 Likes
Hi @aleksander.stanik,
That’s great - thanks very much for sharing the full example. I’m sure that will be helpful for others!
[quote=“daviesian, post:2, topic:9217”]
Store the JSON key as an App Secret
[/quote].
Can you please ellaborate on how we can do this?
Hey, just wanted to say that this post helped me out a ton, thanks.
1 Like