How to get userinfo with google-api after succesfully been authenticated? - java

I try to get the userinfo after successfully authenticate with a gmail account (tok is a valid token):
GoogleCredential credential2 = new GoogleCredential.Builder()
.setTransport(TRANSPORT).setJsonFactory(JSON_FACTORY)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.setRequestInitializer((new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request)
throws IOException {
request.getHeaders().setAuthorization("Bearer ".concat(tok));
}
}))
.build();
Oauth2 userInfoService = new Oauth2.Builder(TRANSPORT,
JSON_FACTORY, credential2.getRequestInitializer())
.setApplicationName(APPLICATION_NAME).build();
Userinfo userInfo = userInfoService.userinfo().get().execute();
logger.warn("User email: {}", userInfo.getEmail());
logger.warn("User gender: {}", userInfo.getGender());
logger.warn("User complet name: {} - {}", userInfo.getFamilyName(), userInfo.getName());
But logs display 'null' for all fields, the json data returned contains only the id:
{
"id": "113695880661351193041"
}
What i'm supposed to do ? Add a special scope to do this? I tried it several times without success, just by adding scope=https://www.googleapis.com/auth/userinfo.profile as url parameter, maybe that's wrong ?
Hope someone can help or know how to add scopes to my request and get the correct response from this service.

This works for me :
Credential credential = OAuth2Utils.newFlow().loadCredential(userId);
Oauth2 service = new Oauth2.Builder(OAuth2Utils.HTTP_TRANSPORT, OAuth2Utils.JSON_FACTORY, credential).setApplicationName("appname").build();
UserInfo userInfo = service.userinfo().get().execute();
These are some of the properties that are returned :
userInfo.getBirthday()
userInfo.getFamilyName()
userInfo.getGender()
userInfo.getGivenName()
userInfo.getHd()
userInfo.getLink()
The utility class OAuth2Utils referred in the code :
/** Global instance of the HTTP transport. */
public final static HttpTransport HTTP_TRANSPORT = new UrlFetchTransport();
/** Global instance of the JSON factory. */
public final static com.google.api.client.json.JsonFactory JSON_FACTORY = new com.google.api.client.json.jackson2.JacksonFactory();
public static GoogleAuthorizationCodeFlow newFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, getClientCredential(),
Arrays.asList(SCOPES)).setCredentialStore(new OAuth2CredentialStore()).setAccessType("offline")
.setApprovalPrompt("force").build();
}

Related

Insufficient Permission: Request had insufficient authentication scopes. Google Drive

i tries to add member to my google sheet using java code, but it doesn't work.
I use OAuthor 2.
Can anyone help me with this problem? Thanks very much.
My code:
public static void main(String... args) throws IOException, GeneralSecurityException {
// Build a new authorized API client service.
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
final String spreadsheetId = "10gLncj6bGmm-UcXP1vztsbv23CD85GNG95zjDgZ8HBA";
JsonBatchCallback<Permission> callback = new JsonBatchCallback<Permission>() {
#Override
public void onFailure(GoogleJsonError e,
HttpHeaders responseHeaders)
throws IOException {
// Handle error
System.err.println(e.getMessage());
}
#Override
public void onSuccess(Permission permission,
HttpHeaders responseHeaders)
throws IOException {
System.out.println("Permission ID: " + permission.getId());
}
};
Drive driveService = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build();
BatchRequest batch = driveService.batch();
Permission userPermission = new Permission()
.setType("user")
.setRole("reader")
.setEmailAddress("trilo10101990#gmail.com");
driveService.permissions().create(spreadsheetId, userPermission)
.setFields("id")
.queue(batch, callback);
batch.execute();
}
Out put :
Insufficient Permission: Request had insufficient authentication scopes.
Insufficient Permission: Request had insufficient authentication scopes.
Means that the user you have authenticated the application with has not granted your application enough scopes to access the data you are trying to access.
You appear to be using Permissions.create this method requires that the user be authorized with one of the following scopes
You didn't post all of your authorization code You probably have something like this.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow
.Builder(httpTransport, JSON_FACTORY, clientSecrets,
DriveScopes.all()).setDataStoreFactory(dataStoreFactory)
.build();
The trick is to look for which scope you are requesting in the case of the code above it is requesting full access to google drive. You need to check your scope and ensure that you have requested full access.
After that you need to remove the users consent to your application and force it to request access of the user again. The user needs to see the consent screen in order to verify their consent.

Unable to have concurrent log-ins with Google auth

I have a web app where users have to authenticate using Google sign-in. I do this because I need to grab their email address. When they fill out the fields on the page, all that data is stored in a google sheet alongside their email address (for auditing purposes incase something is askew with the data). Unfortunately what's happening is that if user A signs in, and does some work and at the same time user B logs in, when user A submits data, they will be submitting user B's email address (as does user B). In short, the latest person to log in, that email address is used. There is no database and I'm not storing any cookies. When they refresh the page, they have to re-authenticate. I am using Angular 7 and Java. Here is the code that I used:
ngOnInit() {
gapi.load('auth2', () => {
this.auth2 = gapi.auth2.init({
client_id: 'CLIENT_ID_HERE',
// Scopes to request in addition to 'profile' and 'email'
scope: 'https://www.googleapis.com/auth/spreadsheets'
});
});
}
signInWithGoogle(): void {
this.auth2.grantOfflineAccess().then((authResult) => {
this.authCode = authResult['code'];
this.fetchData();
});
}
authCode is bound to the child component so it can be passed as query param to the java code for google auth.
this.seriesService.submitSeriesData(matchList, this.authToken).subscribe(res => {.....);
The google auth java code is so:
private static final String APPLICATION_NAME = "Google Sheets API Java";
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final List<String> SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS);
private static final String CLIENT_SECRET_DIR = "/client_secret.json";
private static GoogleTokenResponse tokenResponse = null;
public static String getEmailAddress() throws IOException {
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String email = payload.getEmail();
return email;
}
public static Sheets getSheetsService1(String token, String redirectUri) throws IOException, GeneralSecurityException {
// Exchange auth code for access token
InputStream in = GoogleAuthUtil.class.getResourceAsStream(CLIENT_SECRET_DIR);
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
"https://www.googleapis.com/oauth2/v4/token",
clientSecrets.getDetails().getClientId(),
clientSecrets.getDetails().getClientSecret(),
token,
redirectUri)
.execute();
String accessToken = tokenResponse.getAccessToken();
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Sheets service = new Sheets.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
.setApplicationName("MY APP HERE")
.build();
return service;
}
And the endpoint:
#RequestMapping(value="series/data", method = RequestMethod.POST, consumes="application/json")
public boolean submitSeriesMatchData(#RequestBody(required=true) SubmitStatsDto request) throws IOException, GeneralSecurityException, Exception {
if (service == null) {
service = GoogleAuthUtil.getSheetsService1(request.getToken(), this.redirectUri);
}
......
}
1) User clicks on the google sign in button
2) They select email and auth with google
3) I receive an auth code back and store it in ng.
4) Every REST call is passed said token to auth with google, and every endpoint calls getSheetsService1 which authenticates w/ token. (multiple endpoints, I only showed one above)
5) I get email from that tokenResponse.
Any ideas? This site will not have a database/users/local logins. Thank you.

Google Reseller API getting GoogleJsonResponseException: 403 Forbidden

I'm working on a project that uses the Google Apps Reseller API (Found here).
I'm running into a 403 Forbidden Exception.
Code (most of it origins from the Google Codelab Example Here:
try {
try {
Reseller service = GoogleResellerApiUtil.getResellerService();
Customer customerRecord = service.customers().get("acme.com").execute(); //crashes here
// "acme.com" is also used in the example from Google
System.out.println(customerRecord.toString());
} catch (GoogleJsonResponseException e) {
e.printStackTrace();
}
And this is the class I use to connect to the API.
I've provided a p12 file and it uses the service account, when calling the API it is impersonating one of the super admins, so it should be allowed to make all the calls.
At the moment I'm only using the read-only scope.
public class GoogleResellerApiUtil {
/** HTTP_TRANSPORT */
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/** JSON Factory*/
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
/** Service Account Email */
public static final String SERVICE_ACCOUNT_EMAIL = "****#appspot.gserviceaccount.com";
/** P12 File Location */
public static final String PRIVATE_KEY_FILE = "WEB-INF/key.p12";
/** Reseller Admin Account to impersonate */
public static final String RESELLER_ADMIN = "**.**#**.com";
/** Scopes */
public static final List<String> SCOPES = Arrays.asList(ResellerScopes.APPS_ORDER_READONLY);
/** Application name. */
private static final String APPLICATION_NAME = "**-subscription-portal";
/** Logger */
private final static Logger LOGGER =
Logger.getLogger(GoogleResellerApiUtil.class.getName());
public static GoogleCredential getCredentials() throws IOException {
GoogleCredential credentials = null;
try {
credentials = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(SCOPES)
.setServiceAccountUser(RESELLER_ADMIN)
.setServiceAccountPrivateKeyFromP12File(new File(PRIVATE_KEY_FILE))
.build();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
System.out.println("credential has been build, returning credential "); //this gets printed, so I think the credentials are valid?
return credentials;
}
/**
* Build and return an authorized Reseller client service.
* #return an authorized Reseller client service
* #throws IOException
*/
public static Reseller getResellerService() throws Exception {
Credential credential = getCredentials();
return new Reseller.Builder(
HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
}
But I get the following error message when making the call:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 OK
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Forbidden",
"reason" : "forbidden"
} ],
"message" : "Forbidden"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
etc. etc. etc.
It is noted in Reseller API: Manage Subscriptions that
Note: If the customerAuthToken is not valid or has expired, the API response returns a 403 "Forbidden" error.
To solve the issue, please make sure that requests must be authorized by an authenticated user who has access to the data. As also noted in Reseller API: Authorizing
Note: The user granting permission for the Reseller API must be a domain super administrator.
In addition to that, it was suggested in Token expiration that you write your code to anticipate the possibility that a granted token might no longer work. A token might stop working for one of these reasons:
The user has revoked access.
The token has not been used for six months.
The user changed passwords and the token contains Gmail scopes.
The user account has exceeded a certain number of token requests.
Hope that helps!

Invalid channel Id return by youtube service api

I am trying to get a list of my youtube channels from a java app using the com.google.api.services.youtube.YouTube class. .
First of all I have enabled the Service Account credentials (https://console.developers.google.com > Credentials ) and I have enabled the following apis :
-YouTube Analytics API
-YouTube Data API
-Analytics API
To make a call to the Youtube service I create a Credential object using the following code.
/** Global instance of the HTTP transport. */
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static Credential authorize() throws Exception
{
List<String> scopes = new ArrayList<String>();
scopes.add("https://www.googleapis.com/auth/youtube");
scopes.add("https://www.googleapis.com/auth/yt-analytics.readonly");
scopes.add("https://www.googleapis.com/auth/youtube.readonly");
scopes.add("https://www.googleapis.com/auth/youtubepartner-channel-audit");
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountPrivateKeyFromP12File(new File("C://file.privatekey.p12"))
.setServiceAccountId("xxxx-yyyyyyyyyyyyyy#developer.gserviceaccount.com")
.setServiceAccountScopes(scopes)
.build();
return credential;
}
After that I call the Youtube service to get my channels
/** Global instance of the HTTP transport. */
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
/** Global instance of Youtube object to make general YouTube API requests. */
private static YouTube youtube;
/** Global instance of YoutubeAnalytics object to make analytic API requests. */
private static YouTubeAnalytics analytics;
public String getDefaultChannelId(){
try{
Credential credential = authorize();
// YouTube object used to make all non-analytic API requests.
youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("API Project")
.build();
YouTube.Channels.List channelRequest = youtube.channels().list("id,snippet");
channelRequest.setMine(true);
channelRequest.setMaxResults(50L);
channelRequest.setFields("items(id,snippet/title,contentDetails,status,kind,etag,auditDetails)");
ChannelListResponse channels = channelRequest.execute();
System.out.println(channels.getItems());
// List of channels associated with user.
List<Channel> listOfChannels = channels.getItems();
// Grab default channel which is always the first item in the list.
Channel defaultChannel = listOfChannels.get(0);
String channelId = defaultChannel.getId();
return channelId;
}catch(Exception ex){
ex.printStacktrace();
}
}
The authorization code seems to work without any problem. The problem is with the getDefaultChannelId() method which returns a channel with id UC9i22sTxrX0IQk4AkT_Og3w .
I tried to navigate using the browser to my youtube channel using tha url : http://www.youtube.com/channel/UC9i22sTxrX0IQk4AkT_Og3w but the channel does not exist..
The line I used to print the channels results "System.out.println(channels.getItems());" displays the following json string.
[{"etag":"\"BDC7VThyM9nfoSQm1_kOyhtJTEw/yJvLzly7DMctrvFV5drOtgksadM\"","id":"UC9i22sTxrX0IQk4AkT_Og3w","kind":"youtube#channel","snippet":{"title":""}}
For some reason the youtube service does not return the right list of channels for the specific credential object.
But why????
You can not use Service Account with Youtube API : https://developers.google.com/youtube/v3/guides/moving_to_oauth#service_accounts. Youtube API is supposed to raise an error with service account but apparently it doesn't.
You should instead create a client ID of type Installed Application then retrieve a refresh token for your user (https://developers.google.com/accounts/docs/OAuth2InstalledApp) and use this token to create credentials.
Here is an example (store clientId, clientSecret, refreshToken and accessToken wherever you like, as soon as you keep it secret, token response should be cached) :
private String clientId;
private String clientSecret;
private String refreshToken;
private String accessToken;
private TokenResponse tokenResponse;
private Credential createCredential() {
final GoogleCredential.Builder builder = new GoogleCredential.Builder();
builder.setTransport(HTTP_TRANSPORT);
builder.setJsonFactory(JSON_FACTORY);
builder.setClientSecrets(clientId, clientSecret);
builder.addRefreshListener(new CredentialRefreshListener() {
#Override
public void onTokenResponse(final Credential credential,
final TokenResponse tokenResponse) throws IOException {
this.tokenResponse = tokenResponse;
}
#Override
public void onTokenErrorResponse(final Credential credential,
final TokenErrorResponse tokenErrorResponse)
throws IOException {
this.tokenResponse = null;
// trace error
}
});
return builder.build();
}
private YouTube getYoutube() {
final Credential credential = createCredential();
if (this.tokenResponse == null) {
credential.setAccessToken(this.accessToken);
credential.setRefreshToken(this.refreshToken);
} else {
credential.setFromTokenResponse(this.tokenResponse);
}
final YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT,
JSON_FACTORY, credential).setApplicationName("*****").build();
return youtube;
}

Java Google Plus Access via oAuth 2.0

I tried many different things to access a google Account in order to read out profile-data, but it failed every time.
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError"
} ],
"message" : "Invalid Credentials"
}
I tried to access via following code
#SuppressWarnings("deprecation")
public static GoogleAccessProtectedResource connect(String CLIENT_ID,String CLIENT_SECRET,String SCOPE,String CALLBACK_URL,HttpTransport TRANSPORT,JsonFactory JSON_FACTORY) throws IOException{
// Generate the URL to which we will direct users
String authorizeUrl = new GoogleAuthorizationRequestUrl(CLIENT_ID,
CALLBACK_URL, SCOPE).build();
System.out.println("Paste this url in your browser: " + authorizeUrl);
// Wait for the authorization code
System.out.println("Type the code you received here: ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String authorizationCode = in.readLine();
// Exchange for an access and refresh token
GoogleAuthorizationCodeGrant authRequest = new GoogleAuthorizationCodeGrant(TRANSPORT,
JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authorizationCode, CALLBACK_URL);
authRequest.useBasicAuthorization = false;
AccessTokenResponse authResponse = authRequest.execute();
String accessToken = authResponse.accessToken;
GoogleAccessProtectedResource access = new GoogleAccessProtectedResource(accessToken,
TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authResponse.refreshToken);
HttpRequestFactory rf = TRANSPORT.createRequestFactory(access);
System.out.println("Access token: " + authResponse.accessToken);
// Make an authenticated request
GenericUrl shortenEndpoint = new GenericUrl("https://www.googleapis.com/urlshortener/v1/url");
String requestBody =
"{\"longUrl\":\"http://farm6.static.flickr.com/5281/5686001474_e06f1587ff_o.jpg\"}";
HttpRequest request = rf.buildPostRequest(shortenEndpoint,
ByteArrayContent.fromString("application/json", requestBody));
HttpResponse shortUrl = request.execute();
BufferedReader output = new BufferedReader(new InputStreamReader(shortUrl.getContent()));
System.out.println("Shorten Response: ");
for (String line = output.readLine(); line != null; line = output.readLine()) {
System.out.println(line);
}
// Refresh a token (SHOULD ONLY BE DONE WHEN ACCESS TOKEN EXPIRES)
//access.refreshToken();
//System.out.println("Original Token: " + accessToken + " New Token: " + access.getAccessToken());
return access;
}
Then i want to access my account
public static void getData1(String accessToken, String clientId, String clientSecret, String refreshToken) throws IOException{
// Set up the HTTP transport and JSON factory
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
// Set up OAuth 2.0 access of protected resources
// using the refresh and access tokens, automatically
// refreshing the access token when it expires
GoogleAccessProtectedResource requestInitializer =
new GoogleAccessProtectedResource(accessToken, httpTransport,
jsonFactory, clientId, clientSecret, refreshToken);
// Set up the main Google+ class
Plus plus = Plus.builder(httpTransport, jsonFactory)
.setHttpRequestInitializer(requestInitializer)
.build();
// Make a request to access your profile and display it to console
Person profile = plus.people().get("[myID]").execute();
System.out.println("ID: " + profile.getId());
System.out.println("Name: " + profile.getDisplayName());
System.out.println("Image URL: " + profile.getImage().getUrl());
System.out.println("Profile URL: " + profile.getUrl());
}
Following main method should work afterwards: CLIENT_ID and CLIENT_SECRET are created
public static void main(String[] args) throws IOException {
GoogleAccessProtectedResource access1=Connection.connect(CLIENT_ID, CLIENT_SECRET, SCOPE, CALLBACK_URL, TRANSPORT, JSON_FACTORY);
//refresh
String token= access1.getAccessToken();
access1.refreshToken();
String refreshed=access1.getAccessToken();
//get data
Connection.getData1(token, CLIENT_ID, CLIENT_SECRET, refreshed);
}
This is my Data...
private static final String SCOPE = "https://www.googleapis.com/auth/urlshortener";
private static final String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";
private static final HttpTransport TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
// FILL THESE IN WITH YOUR VALUES FROM THE API CONSOLE
private static final String CLIENT_ID = "[myID].apps.googleusercontent.com";
private static final String CLIENT_SECRET = "[myID]";
Now there is a bad Request Exception thrown
Exception in thread "main" com.google.api.client.http.HttpResponseException: 400 Bad Request
{
"error" : "invalid_client"
}
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:900)
at com.google.api.client.auth.oauth2.draft10.AccessTokenRequest.executeUnparsed(AccessTokenRequest.java:472)
at com.google.api.client.auth.oauth2.draft10.AccessTokenRequest.execute(AccessTokenRequest.java:486)
at Connection.connect(Connection.java:78)
at Connection.main(Connection.java:50)
This is hopefully pretty easy to fix.
You're using a SCOPE string of:
https://www.googleapis.com/auth/urlshortener
This is the scope for the URL Shortener (goo.gl) API, not the Google+ APIs. Instead you should probably try using the profile scope for Google+
https://www.googleapis.com/auth/plus.me
Documentation here:
https://developers.google.com/+/api/oauth
Above, it looks like you're using [myID] to reference two different types of ID:
In the below statement, the myID should be your Google+ profile ID (copied/pasted from the URL for your Google+ profile or instead use the string 'me' to represent the currently authorized user):
Person profile = plus.people().get("[myID]").execute();
However, for the CLIENT_ID, you should be using the values from your project in code.google.com/apis/console.

Categories