I am facing and issue while requesting a cab through Uber Api with Python.
These are the steps I have followed :
Creating a session with my server_token.
Authorizing with my credentials.
Got authorization_url and user authentication is done.
Created an object with a session I got from user authentication.
Got the credentials using the method :
credentials = new_session.oauth2credential
Estimation for the ride :
estimate = client.estimate_ride(product_id=PRODUCT_ID,
start_latitude=xx.xxx, start_longitude=xx.xxx, end_latitude=xx.xxx, end_longitude=xx.xxx)
Fetching fare Amount :
fare = estimate.json.get('fare')
I try to request a ride with below code and get the exception :
response = client.request_ride(product_id=Product_ID,
start_latitude=xx.xxx, start_longitude=xx.xxx, end_latitude=xx.xxx, end_longitude=xx.xxx, fare_id=fare.get('fare_id'))
Exception :
ClientError: 401: This endpoint requires at least one of the following scopes: request.delegate.tos_accept, request, request.delegate
Please let me know where am I going wrong. Did I miss any step ?
Thanks in advance.
The issue is you need to add the 'request' privileged scope when creating the token.
from uber_rides.auth import AuthorizationCodeGrant
auth_flow = AuthorizationCodeGrant(
<CLIENT_ID>,
<SCOPES>,
<CLIENT_SECRET>,
<REDIRECT_URI>
)
auth_url = auth_flow.get_authorization_url()
See more details in the python ride requests tutorial.
Related
I have a desktop Java app that I am migrating from Google Contacts API to People API. I have some of it working. For example, I can retrieve contact information. But when I tried to create a new contact, I get the following error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
POST https://people.googleapis.com/v1/people:createContact
{
"code" : 403,
"details" : [ {
"#type" : "type.googleapis.com/google.rpc.ErrorInfo",
"reason" : "ACCESS_TOKEN_SCOPE_INSUFFICIENT"
} ],
"errors" : [ {
"domain" : "global",
"message" : "Insufficient Permission",
"reason" : "insufficientPermissions"
} ],
"message" : "Request had insufficient authentication scopes.",
"status" : "PERMISSION_DENIED"
}
Here's the relevant code:
protected void createContact() throws Exception {
Credential credential = authorize(PeopleServiceScopes.CONTACTS, "people");
PeopleService service = new PeopleService.Builder(
httpTransport, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
Person contactToCreate = new Person();
List<Name> names = new ArrayList<Name>();
names.add(new Name().setGivenName("John").setFamilyName("Doe"));
contactToCreate.setNames(names);
Person createdContact = service.people().createContact(contactToCreate).execute();
System.out.println("CREATED Contact: " + createdContact.getNames().get(0).getDisplayName());
}
protected Credential authorize(String scope, String subDir) throws Exception {
File dataStoreDir = new File(System.getProperty("user.home"), ".store/myapp/" + cfg.dataStore + "/" + subDir);
// initialize the transport
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// initialize the data store factory
dataStoreFactory = new FileDataStoreFactory(dataStoreDir);
// load client secrets
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(SyncMgr.class.getResourceAsStream("/client_secrets.json")));
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
System.out.println(
"Enter Client ID and Secret from https://code.google.com/apis/console/?api=calendar "
+ "into /client_secrets.json");
System.exit(1);
}
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(scope)).setDataStoreFactory(dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize(cfg.gUser);
}
When I first ran it, I had the scope set to CONTACTS_READONLY. And I got the consent screen. But then I changed the scope to CONTACTS when I added the code to create a new contact. And that's when I got the ACCESS_TOKEN_SCOPE_INSUFFICIENT error.
I saw in another post that I need to force your app to reauthorize the user when you change the scope, so that you get the consent screen again. But I'm not sure how to do that. Any suggestions?
Thanks.
UPDATE 1/4/22
I tried Gabriel's suggestion of removing access to the application. After removing access, I ran the application again. This time I got this error on the execute() call:
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
POST https://oauth2.googleapis.com/token
{
"error" : "invalid_grant",
"error_description" : "Token has been expired or revoked."
}
And even the execute() statement that worked before to retrieve contacts is giving the same error now.
My application also used the Calendar API. I didn't touch that code. But when I try to use it, I get the same "invalid_grant" error. What do I do now?
You appear to be using the People.createContact method. If we take a look at the documentation we will see that this method requires a consent to the following scope of permissions from the user
Now if we check your code you apear to be using
Credential credential = authorize(PeopleServiceScopes.CONTACTS, "people");
Which is the exact scope needed. But you oringally had readonly there. So when your code ran the first time the user authorized to the read only scope and not the full contacts scope and your stuck.
The key here is this section of code.
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(scope)).setDataStoreFactory(dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize(cfg.gUser);
Kindly note I am not a Java developer I am a .net developer. The libraries are very close and i have been helping with questions this in both languages for years.
dataStoreFactory is where the consent from the user is stored. There should be a json file some where in your directory structure with the users name associated with it this is how your system reloads it. When your code runs it will look for a file in that directory with cfg.gUser name.
There should be a way in the Java client library to force it to rerequest authorization of the user. prompt type force. But i will have to look around to see how to do it in java.
The easiest solution now would be to find that directory and delete the file for the user or just change the users name cfg.gUser to cfg.gUser +"test" or something this will cause the name to change and the file name as well. Forcing it to prompt the user for authorization again.
This time when it requests consent take note which scope of permissions it asks for.
Token has been expired or revoked.
This is probably due to the fact that your refresh tokens are expiring. When your application is in the testing phase the refresh tokens are expired or revoked automatically by google after seven days.
This is something new and something that Google added in the last year or so. Unfortunately the client libraries were not designed to request access again if the refresh token was expired in this manner.
If you are looking to retrieve the consent screen again you can remove access to your application from your account settings by following the steps in this documentation and then try to authorize the app again. As you mentioned, the error received is due to the scope that was granted with authorization was CONTACTS_READONLY instead of CONTACTS when checking the authorization scope for this specific create contacts method.
I have a service account with domain wide delegation setup and I'm trying to create new accounts(google-api-services-admin-directory) using the service account and then add some preset calendars(google-api-services-calendar) to the newly created accounts.
I've had no problems with the directory api. I've had to create a delegated (Admin) User using the service account and all the directory-api calls work fine.
However, I've been having trouble in getting the calendar-api calls to work.
Java dependencies:
compile group: 'com.google.auth', name: 'google-auth-library-oauth2-http', version:'0.20.0'
compile group: 'com.google.apis', name: 'google-api-services-admin-directory', version:'directory_v1-rev53-1.20.0'
compile group: 'com.google.apis', name: 'google-api-services-calendar', version:'v3-rev20200315-1.30.9'
Java code:
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final List<String> SCOPES =
Arrays.asList(DirectoryScopes.ADMIN_DIRECTORY_USER, DirectoryScopes.ADMIN_DIRECTORY_GROUP,
CalendarScopes.CALENDAR);
private static final String CREDENTIALS_FILE_PATH = "config/google-service-account-credentials.json";
.....
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
sourceCredentials =
ServiceAccountCredentials.fromStream(new FileInputStream(CREDENTIALS_FILE_PATH));
sourceCredentials = (ServiceAccountCredentials) sourceCredentials.createScoped(SCOPES);
.....
GoogleCredentials targetCredentials = sourceCredentials.createDelegated("newuser#email");
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(targetCredentials);
targetCredentials.refreshIfExpired();//Not sure if this is required. It didn't help though
Calendar calendarService = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer).setApplicationName(MainApp.SERVICE_NAME).build();
for (String calendarKey : listOfCalendars)) {
CalendarListEntry cle = new CalendarListEntry();
cle.setId(calendarKey);
calendarService.calendarList().insert(cle).execute();//Fails with a 401
}
Stack Trace :
Caused by: java.io.IOException: Error getting access token for service account: 401 Unauthorized
at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:444)
at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:157)
at com.google.auth.oauth2.OAuth2Credentials.refreshIfExpired(OAuth2Credentials.java:174)
at myApp.GSuiteSDKHelper.updateDefaultCalendars(GSuiteSDKHelper.java:169)
... 65 more
Caused by: com.google.api.client.http.HttpResponseException: 401 Unauthorized
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:441)
... 68 mo
And the interesting part is that the error is intermittent. After a redeploy, I can always get my first attempt to work. Following that, it is a hit or miss.
I did add the service account to the calendars that I'm trying to add and also ensure the service account is an "owner" on the calendars.
Something similar happened to me, in my case I could solve it by adding the scopes: "https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/userinfo.profile"
I am getting the following error
Whoa there!
The request token for this page is invalid. It may have already been used, or expired because it is too old. Please go back to the site or application that sent you here and try again; it was probably just a mistake
1) The following method in which we are calling the twitter credentials to your Api
2)The callback function is static
3) i am using Oauth 1 and using google cloud for hosting
4)I have already cleared the cache 2 times still no use
.def _twitter(self):
# Get the access token supplied
oauth_token = self.test_credentials.get('oauth_token')
oauth_token_secret = self.test_credentials.get('oauth_token_secret')
if not oauth_token or not oauth_token_secret:
raise AuthenticationException('Invalid request format.', 400)
auth = tweepy.OAuthHandler(current_app.config['TWITTER_CONSUMER_KEY'], current_app.config['TWITTER_CONSUMER_SECRET'])
auth.set_access_token(oauth_token, oauth_token_secret)
api = tweepy.API(auth)
user = api.verify_credentials()
if not user:
raise AuthenticationException('Unable to verify credentials with remote server.', 500)
# Save the user
auth_string = self._auth_string(unicode(user.id_str))
stored_user = User.query(User.auth_ids == auth_string).get()
if not stored_user:
return User(name=user.name)
if stored_user and not stored_user.name:
stored_user.name = user.name
stored_user.put()
return stored_user
I forgot to add my callback function in the twitter api callbacks (these resolved my error)
I have implemented the python code here below based on the documentation in order to access a spreadsheet accessible through a public link.
It works once every hour. If I execute a few seconds after a success, I receive an error :
Error opening spreadsheet no element found: line 1, column 0
Assumption:
The access token has an expiry date of 1 hour. So the appengine would proceed to a token refresh after an hour, resetting the whole.
Question:
This code requests a new token for each request. So what should I do ? Save the token ? When I try the token_to_blob in order to save the token, I get an error :
Scope undefined
Thanks in advance for your help !
try :
credentials = AppAssertionCredentials(scope=('https://www.googleapis.com/auth/drive','https://spreadsheets.google.com/feeds','https://docs.google.com/feeds'))
logging.info("credentials")
http_auth = credentials.authorize(httplib2.Http())
authclient = build('oauth2','v2',http=http_auth)
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
except Exception as details:
logging.error("Error Google credentials %s"%details)
return "Error"
try :
gd_client = gdata.spreadsheets.client.SpreadsheetsClient()
gd_client = auth2token.authorize(gd_client)
feed = gd_client.GetListFeed(<spreadsheetKey>,1)
except Exception as details:
logging.error("Error opening spreadsheet %s"%details)
return "Error"
I finally declared the credentials & the token as global.
In this case, it was working for several subsequent requests but after 1 hour, the token was invalid.
I tested with the method access_token_expired but this method always returned false.
So, I finally execute the refresh systematically and it works. Not elegant but functional. Another option would be to store the time of next refresh and only refresh after 1 hour.
Your comments are welcome for elegant alternatives.
I did not try gspread since the rest of the code was already functional for gdata.spreadsheets but perhaps I should.
from oauth2client.contrib.appengine import AppAssertionCredentials
from oauth2client.client import Credentials
from oauth2client.service_account import ServiceAccountCredentials
from googleapiclient.discovery import build
import httplib2
global credentials
global auth2token
try :
credentials = AppAssertionCredentials(scope=('https://www.googleapis.com/auth/drive','https://spreadsheets.google.com/feeds','https://docs.google.com/feeds'))
http_auth = credentials.authorize(httplib2.Http())
authclient = build('oauth2','v2',http=http_auth)
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
except Exception as details:
logging.error("Error Google credentials %s"%details)
class importFromSpreadsheet(webapp2.RequestHandler):
def __importFromSpreadsheet(self,u):
try :
credentials._refresh(httplib2.Http())
except Exception as details:
logging.error("Error refreshing Google credentials %s"%details)
...
try :
gd_client = gdata.spreadsheets.client.SpreadsheetsClient()
gd_client = auth2token.authorize(gd_client)
feed = gd_client.GetListFeed(u,1)
except Exception as details:
logging.error("Error opening 1st spreadsheet %s"%details)
return "Error"
I'm using Django-socila-auth plugin. It uses google API for Oauth 1.0 Authentication. Question is have anybody used it with google python API (gdata). I mean how to apply auth session_token, stored in django-social-auth model to my api call.
Can you help me with code to get this token from model and apply to gdata.PhotoService() instance. For now it is like this:
#getting model instance from django-social-auth model
association = Association.objects.get(user=request.user)
google_session_token=association.handle
google_secret=association.secret
#token string from django-social-auth
#model Association field "handle" looks like:
#google_session_token = '.......XG84PjwytqJkvr8WQhDxm1w-JplWK5zPndSHB13f.........'
gd_client = gdata.photos.service.PhotosService()
gd_client.debug = 'true'
gd_client.auth_token = google_session_token
#image.image is a file field, but problem not in this.
#it tries to send file in debug text.
#It just recieves 403 unauthorised callback.
photo = gd_client.InsertPhotoSimple(
'/data/feed/api/user/default/albumid/default', 'New Photo',
'Uploaded using the API', image.image, content_type='image/jpeg')
I'm recieving error
403 Invalid token string.
I understand that it needs secret too but how to apply it to API for auth?(To receive authorization to post photos.). BTW I added Picassa feed URL, as an option string for social-auth to ask permissions, so token I have asks for Picassa feed permissions when authorizing with google.
BTW. Google tutorial I've used is: here
I understand it's Oauth 1.0 rather than AusSub, but question is:
how to authenticate with token and secret I have and post a photo with this permission?
Just to answer my own problem. I used wrong way to do it, because problem in 'gd_client' and AuthSub.
It must check token on server. And it can not do it on localhost. You need to look ahead to Oauth/Oauth2 for better debugging and so on... No matter that it is much complex than AuthSub