My question is very similar to moment.insert from python code but Fausto has already managed to get further than me so I'm unable to apply that answer at this time.
My code looks like this, and my question is "how do I post to my g+ profile"
user = 'awarner#######.com'
key = open(keyFile, 'r').read()
credentials = SignedJwtAssertionCredentials(
'##########developer.gserviceaccount.com',
key,
scope='https://www.googleapis.com/auth/plus.login',
sub=user)
http = httplib2.Http()
http = credentials.authorize(http)
service = build(serviceName='plus', version='v1', http=http)
# Not really required here but these calls demonstrate that we are authenticated
searchResults = service.people().search(query='AlistairWarner').execute()
listMoments = service.moments().list(userId='me', collection='vault').execute()
moment = { "type" : "http://schemas.google.com/AddActivity",
"target" : {
"id" : "target-id-1",
"type" : "http://schemas.google.com/AddActivity",
"name" : "The Google+ Platform",
"description" : "A page that describes just how awesome Google+ is!",
"image" : "https://developers.google.com/+/plugins/snippet/examples/thing.png"
}
}
# This call fails with a "401 Unauthorized" error
insertResults = service.moments().insert(userId='me', collection='vault', body=moment).execute()
Just for the record I have confirmed that I have correctly delegated domain-wide authority to my service account for the necessary scopes - although I don't believe that this is really an authorization issue per se because the list call is working. I have also confirmed that my "App" appears on my g+ profile under Apps as mentioned by Prisoner in response to Fausto's question (referenced above).
Looking at the API reference page it does warn that you will get the 401 error that I am seeing. It, and other posts here on StackOverflow (I'd give the ref but not allowed to), say that you need to add the data-requestvisibleactions (again, can't give ref) attribute but I am struggling to see the relevance of the Sign-In Button that they describe attaching it to in my code - which has no UI, I just run it from the command line. So, requestvisibleactions does seem to be the best candidate, I just don't know how to translate that into something that I can use here.
Does anyone have a clue how to get this working?
You need to add this as part of your OAuth request credentials. So it might look something like
credentials = SignedJwtAssertionCredentials(
'##########developer.gserviceaccount.com',
key,
scope='https://www.googleapis.com/auth/plus.login',
requestvisibleactions='http://schemas.google.com/AddActivity',
sub=user)
Related
I'm developing app that is going to be run on a headless server. To launch it I need to possess access and refresh tokens that is done by following request https://developers.upwork.com/?lang=python#authentication_access-token-request. I'm using python, so my request looks like:
import upwork
config = upwork.Config(
{
"client_id": <my_client_id>,
"client_secret": <my_client_secret>,
"redirect_uri": <my_redirect_uri>
}
)
client = upwork.Client(config)
try:
config.token
except AttributeError:
authorization_url, state = client.get_authorization_url()
# cover "state" flow if needed
authz_code = input(
"Please enter the full callback URL you get "
"following this link:\n{0}\n\n> ".format(authorization_url)
)
print("Retrieving access and refresh tokens.... ")
token = client.get_access_token(authz_code)
As a result token object looks like:
{
"access_token": <access_token>,
"refresh_token": <refresh_token>,
"token_type": "Bearer",
"expires_in": 86400
}
Given access_token and refresh_token I put them to my program and it is successfully launched. To keep continuous access to Upwork API I need to have valid access_token which expires every 24 hours, so I renew it with refresh_token. But the problem is than last one's lifespan is 2 weeks and when it's gone I can't use it to refresh access token, so need to get new one. In the documentation I haven't found how to do so and it seems that the only way is to go through the whole process of obtaining tokens pair again as described above, but that's not an option for me because as I said I want to deploy an application on a headless server without ability to redirect user. I need the way to get tokens pair every 2 weeks without manual intervention
Expecting:
Find a way to refresh refresh_token without redirecting user and manual intervention at all
you can set a timer, that is going to call refresh-token a moment before it expires. This is one way to do it. But maybe someone will come up with a better idea. I've seen people doing this with access token, which wasn't a good practice in that case. But you have a different situation.
#sviddo, if there is no activity for 2 weeks, the authentication is required, involving the user manual login. It's a security requirement.
The other thing is that a refresh token is valid for 14 days, and its TTL automatically extended when refresh is performed. If it's not the case, please, contact Support Team at Upwork
I have a Json service file, and a service account that already accesses translate and sheets, but it will not access user lists. The result is either 400 showing its confused or 401 saying its not authorized. Examples are usually about client involved OAuth processes, where I need server to server. I have enabled that "Enable G Suite domain-wide delegation" feature on the service account too.
I read and tried the JWT method, but I get the same error responses.
https://developers.google.com/identity/protocols/oauth2/service-account#python_2
My goal is to call either one of these end points
https://www.googleapis.com/admin/directory/v1/users
https://www.googleapis.com/admin/directory/v1/users.readonly
Any direction would be greatly appreciated.
UPDATE1:
This is using the Jwt token approach which yields error 401.
with open(CLIENT_SECRET_FILE, "r+") as fh:
config = json.load(fh)
iat = time.time()
exp = iat + 3600
payload = {'iss': config['client_email'],
'sub': config['client_email'],
'aud': 'https://www.googleapis.com/',
'iat': iat,
'exp': exp}
additional_headers = {'kid': config['private_key_id']}
signed_jwt = jwt.encode(payload, config['private_key'], headers=additional_headers,
algorithm='RS256')
url = 'https://www.googleapis.com/admin/directory/v1/users'
headers = {"Authorization": "Bearer " + signed_jwt}
r = requests.get(url, headers=headers)
I have also tried
scopes = ['https://www.googleapis.com/auth/admin.directory.user']
credentials = ServiceAccountCredentials.from_json_keyfile_name(CLIENT_SECRET_FILE, scopes=scopes)
service = build('admin', 'directory_v1', credentials=credentials)
results = service.users().list().execute()
UPDATE2:
This link has great information and simple code to review. As much as I tried to avoid impersonation, the AdminSDK requires it. That makes integrations a bit awkward in my view. In addition, the issue I also faced was the Domain-Wide-Delegation screen in the Google Workspace Admin can get messed up. Deleting the entry and recreating it fixed the forever 403 error I kept getting no matter what I had tried.
https://gist.github.com/lewisrodgers/fa766ebd37c1397d3a014eb73805edd1
You need to incorporate into your code impersonation, so that the service account acts on behalf of the admin
Because only admins have authroization to access Resource: users.
For impersonation in Python you need to implement the additional line
delegated_credentials = credentials.with_subject('admin#example.org')
The link below has great information and simple code to review. As much as I tried to avoid impersonation, the AdminSDK requires it. That makes integrations a bit awkward in my view.
In addition, the issue I also faced was the Domain-Wide-Delegation screen in the Google Workspace Admin that messed up. After much digging over weeks, I found a simple solution of deleting and recreating the client entry in that screen. It fixed the never ending 403 error that hit every test I tried that should have worked and did for many others.
This seems to be the only API set by Google that requires impersonation, and is annoying when attempting to create a SaaS solution.
Really basic, trimmed examples, and decent article references.
https://gist.github.com/lewisrodgers/fa766ebd37c1397d3a014eb73805edd1
How to get FT articles via their API ?
After asking for a key I first used a python API wrapper around their content API, v2. So I ran the following:
from pyft import FT
ft = FT()
# the id can be pulled from the slug url of an FT.com story
content = ft.get_content("6f2ca3d6-86f5-11e4-982e-00144feabdc0")
print(content)
And got:
{'error': 'Access to this API has been disallowed'}
So I followed the official instructions but got the same error :
This should be a Bug from FT. Since, the get_content_notifications without any issues.
notification = ft.get_content_notifications("2018-10-10T00:00:00.000Z")
print(notification)
{
"requestUrl": "https://api.ft.com/content/notifications?since=2018-10-10T00%3A00%3A00.000Z",
"notifications": [
{
"type": "http://www.ft.com/thing/ThingChangeType/UPDATE",
"id": "http://www.ft.com/thing/e75d5a6c-b725-11e8-bbc3-ccd7de085ffe",
"apiUrl": "https://api.ft.com/content/e75d5a6c-b725-11e8-bbc3-ccd7de085ffe"
}
}
This is because your API key is under Headline License, which only allows access to limited enpoints. Therefore, you should consider purchasing a Datamining License in order to get access to more enpoints including the "get content" in your code. See more here: https://developer.ft.com/portal/docs-start-obtain-an-api-key
Instructions from FT.com
Download FT_API_Postman_Collection.json
Open Postman
Click Import, click Choose Files and specify FT_API_Postman_Collection.json. An import success message appears for each collection imported
Click the Eye icon to setup an Environment
Click Add
Enter an Environment name. for example, FTAPI
Copy your API Key from the email sent to you in the previous step
Enter a Key and a Value
Click Add
Click Add
When you setup an FTAPI environment, make sure the variable is named 'KEY' as this is what it is called in the Postman collection.json
I am working on a python AppEngine application with Facebook login. I want to be able to access a logged-in user's friends' bios (their "about me" information).
Having requested/saved changes for all of the permissions I need on the Facebook developer's dashboard, I can successfully make calls like this:
friends = graph.get_connections("me", "friends", fields="name")
for friend in friends["data"]:
print friend["name"]
But trying to access the about me, as specified by the "bio" field in the docs, results in a key error:
friends = graph.get_connections("me", "friends", fields="name,bio")
for friend in friends["data"]:
print friend["bio"]
AppEngine log when running on local host:
File "/Users/nicole/aggie-harmony/main.py", line 154, in get
user = self.current_user
File "/Users/nicole/aggie-harmony/main.py", line 108, in current_user
bio = friend["bio"]
KeyError: 'bio'
INFO 2013-11-16 02:59:27,243 module.py:608] default: "GET / HTTP/1.1" 500 -
I have experimented with other fields, and it seems like anything that requires an access token will generate a key error (although the docs actually seem to have been updated mere HOURS before this question was posted...and they now suggest that "Other fields that have been explicitly set to public visibility can also be retrieved without an access token"...in my test user, the bio is indeed public!)
Unless I am just missing something syntax-wise, is this indeed a token issue? My app is based on the example here and basically obtains/uses the access token like this (auth stuff was generated previously and stored in its own file):
...
cookie = facebook.get_user_from_cookie(self.request.cookies, auth.FACEBOOK_APP_ID,
auth.FACEBOOK_APP_SECRET)
...
graph = facebook.GraphAPI(cookie["access_token"])
...
Interestingly enough, the app doesn't pop up a permission box for the user after the log-in area, which might support my hunch...
SOLVED: It was indeed an issue of permissions. In my adapted example html file, I just needed to change this:
function doLogin() {
FB.login(function(response) {} , {perms:''});
}
...to this:
function doLogin() {
FB.login(function(response) {} , {perms:'user_about_me,friends_about_me,user_likes,friends_likes,user_relationship_details,friends _relationship_details,user_relationships,friends_relationships, user_education_history, friends_education_history'});
}
Facebook takes care of the rest with the proper oauth dialog, etc.
I'm trying to share a card ( the html inside it ) from my Glassware using python and the Python Mirror API Quickstart code.
creds = StorageByKeyName(Credentials, '#####', 'credentials').get()
plus_service = util.create_service('plus', 'v1', creds)
moment = {"type":"http://schemas.google.com/AddActivity",
"target": {
"id": "target-id-1",
"type":"http://schemas.google.com/AddActivity",
"name": "The Google+ Platform",
"description": "A page that describes just how awesome Google+ is!",
"image": "https://developers.google.com/+/plugins/snippet/examples/thing.png"
}
}
google_request = plus_service.moments().insert(userId='me', collection='vault', body=moment)
result = google_request.execute()
I got this response back:
HttpError: <HttpError 403 when requesting https://www.googleapis.com/plus/v1/people/me/moments/vault?alt=json returned "Insufficient Permission">
I can understand that is a permission problem but my question is, what is the suggested UI to ask to a glass user for G+ permissions?
Furthermore, by adding "https://www.googleapis.com/auth/plus.login" in the requested permissions I got this:
https://www.googleapis.com/plus/v1/people/me/moments/vault?alt=json returned "Unauthorized">
Thanks in advance
To get G+ access, you can piggyback on the authorization process that Mirror API uses. Make the following modifications to the Mirror API Python Quickstart project:
First, enable the Google+ API in the Google API Console for your project.
Second, in oauth/hander.py, add your G+ scope to the SCOPES list:
SCOPES = ('https://www.googleapis.com/auth/glass.timeline '
'https://www.googleapis.com/auth/glass.location '
'https://www.googleapis.com/auth/userinfo.profile '
'https://www.googleapis.com/auth/plus.login')
Third, revoke your old auth tokens and get fresh ones. Do this by signing out of and signing back into your Quickstart instance's web front end. When you sign in, the sign in page should be updated to list the new Google+ permission:
With these steps, the code you posted should work. Comment if it doesn't and I can help you continue debugging.