Manually authenticate my user account with Google Calendar API v3 - python

What I'm trying to do:
Allow users that are authenticated and authorized on my site to use a form that allows them to create events on my calendar using Google Calendar's API.
I was able to accomplish this through Google Calendar API v2 by manually authenticating my Google account by doing this:
calendar_service = gdata.calendar.service.CalendarService()
calendar_service.email = 'email#site.com'
calendar_service.password = 'password'
calendar_service.source = 'Calendar'
calendar_service.ProgrammaticLogin()
I could then pipe in the POST date from my site's form and create an event using the API, but I'm at a loss for how to do this with V3 of the API.
I have read the documentation and tried implementing:
created_event = service.events().insert(calendarId='primary', body=event).execute()
But this requires that a service object be created, which in turn requires account authentication through OAuth 2.0, which is not what I'm trying to accomplish. I need to manually authenticate my own calendar instead of asking a user if my application can access their calendar.
I'm sure I'm missing some fundamental logic or making some false assumptions. Any help in the right direction would be appreciated.

You have to use OAuth to authorize your code to access your own calendar; once you do that, you'll get a token that you can keep. When your code runs again, it should reuse the token to connect to your calendar. Users won't be challenged, but the token might be refreshed from time to time.
Can't suggest any code because I personally hate OAuth with a passion :(

#Ben - The service object can be created either with a key/secret combination OR using a Service Account where you use a email/cert combination and the prn parameter to identify the user on which you want to operate. Both methods require registration in your API console.
Using a Service Account, you could just specify your email address in the prn parameter to insert the event into your calendar. The insert statement stays the same since you're operating on your account with this specification.
credentials = SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key,
scope='https://www.googleapis.com/auth/calendar', prn='you#domain.com')
...
created_event = service.events().insert(calendarId='primary', body=event).execute()
Here's an example of that: https://developers.google.com/drive/delegation

Related

is there a direct explanation for each google-ads.yaml item?

I am looking for collect data from Google ADS API into GCP by using Python scripts and it requires to fill these items for authentication in the google-ads.yaml file:
developer_token:
client_id:
client_secret:
refresh_token:
login_customer_id:
I was able to fill these items by asking people in my company or generating it with google python scripts in GitHub but I need to understand the role of each, the docs seems to be disperse with a long learning path.
You can follow this guidebook to make your google-ads.yaml file. And for the sample role you provided, below are the definitions of each but you can check this sample template for more details about it.
Developer token
A developer token is required when making requests to the Google Ads API regardless of whether you're using the OAuth2 or Service Account configurations. To obtain a developer token see: https://developers.google.com/google-ads/api/docs/first-call/dev-token
developer_token: INSERT_DEVELOPER_TOKEN_HERE
OAuth2 configuration
The below configuration parameters are used to authenticate using the recommended OAuth2 flow. For more information on authenticating with OAuth2 see:
https://developers.google.com/google-ads/api/docs/oauth/overview
client_id: INSERT_OAUTH2_CLIENT_ID_HERE
client_secret: INSERT_OAUTH2_CLIENT_SECRET_HERE
refresh_token: INSERT_REFRESH_TOKEN_HERE
Login customer ID configuration
Required for manager accounts only: Specify the login customer ID used to authenticate API calls. This will be the customer ID of the authenticated manager account. It should be set without dashes, for example: 1234567890 instead of 123-456-7890. You can also specify this later in code if your application uses multiple manager account + OAuth pairs.
login_customer_id: INSERT_LOGIN_CUSTOMER_ID_HERE

Salesforce API - This session is not valid for use with the REST API - Invalid Session ID

For over a year, I have connected to Salesforce using the simple_salesforce package in order to pull some data from various objects and load it to a data lake.
I have used the authentication method using username / password / security token.
client = Salesforce(
username="****************",
password="*************",
security_token="****************"
)
On the 1st of February came the enforcement of multi factor auth. Starting on that day, I consistently hit the same error over and over.
[{'message': 'This session is not valid for use with the REST API', 'errorCode': 'INVALID_SESSION_ID'}]
After some research, I tried to add a permission set with API Enabled and then API Only user. Result: still the same error, but now I am locked out of the UI.
Has anyone else encountered similar issues and could point me towards the right resources, please? Thanks!
MFA shouldn't matter for API access according to https://help.salesforce.com/s/articleView?id=000352937&type=1 (Ctrl+F "API"), it's probably something else your admin did.
Username, password+token sounds like you're use SOAP login method.
See if you can create a "connected app" in SF to use the OAuth2 login method, more natural for REST API. I wrote a bit about it in https://stackoverflow.com/a/62694002/313628. In the connected app you should be able to allow API access, even full if needed. No idea if Simple has natural place for the keys though, it's bit rubbish if you'll have to craft raw http requests yourself.
Simple's documentation also mentions using JWT to log in (and that requires connected app anyway), basically instead of username + pass you go username + certificate + the fact admin preauthorised this user... You'll be fine until certificate expires.
The text part of https://gist.github.com/booleangate/30d345ecf0617db0ea19c54c7a44d06f can help you with the connected app creation; sample code's probably not needed if you're going with Simple

get auth tokens without using cognito-specific boto APIs

I am currently using AWS Cognito for user authentication. However, I have plans to make AuthN IDP agnostic. For example, I want to be able to replace Cognito with some other identity provider later.
Currently, I use boto3 cognito API to get idToken like below. How can I write a non-cognito specific implementation to get idTokens so that when the provider changes, I won't be relying on cognito? I want to use some generic python OAuth APIs to obtain idToken for the user. How can I do that?
cognito_client = boto3.client('cognito-idp')
response_tokens = cognito_client.initiate_auth(
AuthFlow='USER_PASSWORD_AUTH',
AuthParameters={
'USERNAME': uname,
'PASSWORD': pwd
},
ClientId=OAUTH_AUDIENCE
)
To get ID token from Cognito you need to call a specific API. And if you want to switch to other IDP later, then you need to use other API provided by that IDP. So, APIs are specific to the IDP.
Hence, as at this moment you want token from Cognito, you need to use AWS APIs.
That said, in case by "different IDP" you mean to say "configuring different IDP with Cognito" then I would like to add that, OAuth 2.0 flow can not be made using CLI or SDKs. Cause, OAuth 2.0 flow is a browser based flow and to login with different IDP you need to use browser.

Using Google Calendar API v 3 with Python

Can someone please give me a clear explanation of how to get the Google Calendar API v3 working with the Python Client? Specifically, the initial OAuth stage is greatly confusing me. All I need to do is access my own calendar, read it, and make changes to it. Google provides this code for configuring my app:
import gflags
import httplib2
from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run
FLAGS = gflags.FLAGS
# Set up a Flow object to be used if we need to authenticate. This
# sample uses OAuth 2.0, and we set up the OAuth2WebServerFlow with
# the information it needs to authenticate. Note that it is called
# the Web Server Flow, but it can also handle the flow for native
# applications
# The client_id and client_secret are copied from the API Access tab on
# the Google APIs Console
FLOW = OAuth2WebServerFlow(
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
scope='https://www.googleapis.com/auth/calendar',
user_agent='YOUR_APPLICATION_NAME/YOUR_APPLICATION_VERSION')
# To disable the local server feature, uncomment the following line:
# FLAGS.auth_local_webserver = False
# If the Credentials don't exist or are invalid, run through the native client
# flow. The Storage object will ensure that if successful the good
# Credentials will get written back to a file.
storage = Storage('calendar.dat')
credentials = storage.get()
if credentials is None or credentials.invalid == True:
credentials = run(FLOW, storage)
# Create an httplib2.Http object to handle our HTTP requests and authorize it
# with our good Credentials.
http = httplib2.Http()
http = credentials.authorize(http)
# Build a service object for interacting with the API. Visit
# the Google APIs Console
# to get a developerKey for your own application.
service = build(serviceName='calendar', version='v3', http=http,
developerKey='YOUR_DEVELOPER_KEY')
But (a) it makes absolutely no sense to me; the comment explanations are terrible, and (b) I don't know what to put in the variables. I've registered my program with Google and signed up for a Service Account key. But all that gave me was an encrypted key file to download, and a client ID. I have no idea what a "developerKey" is, or what a "client_secret" is? Is that the key? If it is, how do I get it, since it is actually contained in an encrypted file? Finally, given the relatively simple goals of my API use (i.e., it's not a multi-user, multi-access operation), is there a simpler way to be doing this? Thanks.
A simple (read: way I've done it) way to do this is to create a web application instead of a service account. This may sound weird since you don't need any sort of web application, but I use this in the same way you do - make some queries to my own calendar/add events/etc. - all from the command line and without any sort of web-app interaction. There are ways to do it with a service account (I'll tinker around if you do in fact want to go on that route), but this has worked for me thus far.
After you create a web application, you will then have all of the information indicated above (side note: the sample code above is based on a web application - to use a service account your FLOW needs to call flow_from_clientsecrets and further adjustments need to be made - see here). Therefore you will be able to fill out this section:
FLOW = OAuth2WebServerFlow(
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
scope='https://www.googleapis.com/auth/calendar',
user_agent='YOUR_APPLICATION_NAME/YOUR_APPLICATION_VERSION')
You can now fill out with the values you see in the API console (client_id = the entire Client ID string, client_secret = the client secret, scope is the same and the user_agent can be whatever you want). As for the service line, developerKey is the API key you can find under the Simple API Access section in the API console (label is API key):
service = build(serviceName='calendar', version='v3', http=http,
developerKey='<your_API_key>')
You can then add in a simple check like the following to see if it worked:
events = service.events().list(calendarId='<your_email_here>').execute()
print events
Now when you run this, a browser window will pop up that will allow you to complete the authentication flow. What this means is that all authentication will be handled by Google, and the authentication response info will be stored in calendar.dat. That file (which will be stored in the same directory as your script) will contain the authentication info that the service will now use. That is what is going here:
storage = Storage('calendar.dat')
credentials = storage.get()
if credentials is None or credentials.invalid == True:
credentials = run(FLOW, storage)
It checks for the existence of valid credentials by looking for that file and verifying the contents (this is all abstracted away from you to make it easier to implement). After you authenticate, the if statement will evaluate False and you will be able to access your data without needing to authenticate again.
Hopefully that shines a bit more light on the process - long story short, make a web application and use the parameters from that, authenticate once and then forget about it. I'm sure there are various points I'm overlooking, but hopefully it will work for your situation.
Google now has a good sample application that gets you up and running without too much fuss. It is available as the "5 minute experience - Quickstart" on their
Getting Started page.
It will give you a URL to visit directly if you are working on a remote server without a browser.

Automatically refresh access token with django-social-auth (omab)

I am currently using django-social-auth to manage oauth2 registration with google-oauth2 for access to Google Drive. I have added offline access to my extra_arguments. Therefore Google returns a refresh token and it is stored by django-social-auth. The problem is that django-social-auth never uses this refresh token to update the access token. Therefore the access token expires after one hour, and I can't use it to perform offline requests. I want to keep the access_token valid 24/7 so I can keep my database synced with each users Google Drive.
GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {'access_type':'offline'}
GOOGLE_OAUTH_EXTRA_SCOPE = ['https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/userinfo.profile']
SOCIAL_AUTH_USER_MODEL = 'accounts.GoogleDriveUser'
SOCIAL_AUTH_EXTRA_DATA = True
SOCIAL_AUTH_SESSION_EXPIRATION = False
Is there a way to force django-social auth to update the access_token every time it expires using the refresh_token. I would love to see an example of how this problem could be solved.
It looks like UserSocialAuth objects now have a .refresh_token() method, which allows you to use .tokens and get the updated token.
There's no way directly implemented in django-social-auth at the moment (I've raised a ticket to track it https://github.com/omab/django-social-auth/issues/492), meanwhile this snippet will do the work, it just need to be improved a little to suite your needs.

Categories

Resources