Youtube search fail with GoogleJsonResponseException: 403 Forbidden - youtube-api

This seems like a basic procedure but I don't know what's going wrong.
Error in logcat output:
com.google.api.client.googleapis.json.GoogleJsonResponseException:
403 Forbidden
{
"code" : 403, 02-26
"errors" : [ {
"domain" : "usageLimits",
"message" : "Access Not Configured",
"reason" : "accessNotConfigured"
}
"message" : "Access Not Configured"
I configured in the code.google.com API console the YouTube data API and got a simple access API key for my Android app.
The code is below; the same as the sample code for search:
YouTube youTube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY,
new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest httpRequest) throws IOException {}
})
.setApplicationName("youtubeplayer")
.setYouTubeRequestInitializer(new YouTubeRequestInitializer(DEV_KEY))
.build();
YouTube.Search.List search = youTube.search().list("id,snippet");
//search.setKey(DEV_KEY);
search.setQ(videoName);
search.setType("video");
search.setFields("items(id/kind,id/videoId,snippet/title,snippet/thumbnails/default/url)");
search.setMaxResults(NUMBER_OF_VIDEO);
SearchListResponse searchListResponse = search.execute();
List<SearchResult> searchResultList = searchListResponse.getItems();
This is for Android. I can play videos with the YouTube Android player API, using the same key.

You need to use the Browser Key for accessing Youtube Data API. Android key is used only for Youtube Player.
So just generate the Browser key in the DevConsole and you are good to go.

1) You need to get your SHA1 key with "keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android"
2) In API console: Create a client id with this key and full package name.
3) In API console: Create an Android key with this key and full package name.
4) Enable YouTube Data API v3 from console

Related

401 - Unauthorized Error is coming in apple music api after generating the developer token

I am trying to access API of Apple Music API
(https://developer.apple.com/documentation/applemusicapi).
After creating the JWT developer token, when i try to access the API, An error of 401 - Unauthorized occurs.
I am doing it in the following way :
Registering a new music identifier (https://help.apple.com/developer-account/#/devce5522674?sub=dev0416b9004)
Creating a MusicKit identifier and private key (https://help.apple.com/developer-account/#/devce5522674) also downloading the private key file.
Getting the Kid (Key Id) and issuer (Team Id) .
Running the following code to generate the token :
const jwt = require("jsonwebtoken");
const privateKey = fs.readFileSync("AuthKey_KEY_ID.p8").toString();
const teamId = TEAM_ID_HERE;
const keyId = KEY_ID_HERE;
const jwtToken = jwt.sign({}, privateKey, {
algorithm: "ES256",
expiresIn: "120d",
issuer: teamId,
header: {
alg: "ES256",
kid: keyId
}
});
console.log(jwtToken);```
And after that checking the code using the curl command :
```curl -v -H 'Authorization: Bearer [developer token]' "https://api.music.apple.com/v1/catalog/us/songs/203709340"```
I am not sure what i am missing here. is it something related to access or is it my code.
P.S : I am the Account Holder, so it is not an issue related to role.
Thanks

Delete videos from playlist using YouTube API

I'm trying to delete a video from one of my playlists using the YouTube API. I'm properly authenticated but I'm still getting the following error:
{
"code" : 403,
"errors" : [ {
"domain" : "youtube.playlistItem",
"location" : "id",
"locationType" : "parameter",
"message" : "Forbidden",
"reason" : "playlistItemsNotAccessible"
} ],
"message" : "Forbidden"
}
I'm following the instructions here: https://developers.google.com/youtube/v3/docs/playlistItems/delete
But what I don't understand is where you're supposed to put the playlistID. I see where you put the videoID, but how does it know which playlist to delete from? I think that's my problem. Here is the code in their example, and mine is identical:
// Sample java code for playlistItems.delete
public static void main(String[] args) throws IOException {
YouTube service = getYouTubeService();
try {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("id", "REPLACE_ME");
parameters.put("onBehalfOfContentOwner", "");
YouTube.PlaylistItems.Delete playlistItemsDeleteRequest = youtube.playlistItems().delete(parameters.get("id").toString());
if (parameters.containsKey("onBehalfOfContentOwner") && parameters.get("onBehalfOfContentOwner") != "") {
playlistItemsDeleteRequest.setOnBehalfOfContentOwner(parameters.get("onBehalfOfContentOwner").toString());
}
playlistItemsDeleteRequest.execute();
}
}
There's not even an input for the playlistID in their "try it" section on the page, which also gives the same error. Just onBehalfOfContentOwner and id. I get the same error after putting in a videoID and executing it on the page. Where should I put the playlistID?
Figured it out. And to clarify: I was trying to delete a video from my own playlist and I was properly authenticated (I could add videos just fine).
Basically, I was using the wrong videoId. I was trying to use the short one you see in the url when you play a video (e.g. qNqfYtd3HTg). You need to use the one that comes back from PlaylistItems.list instead (e.g. UEwzdmpFaWdSbm5rQ3hPN29qNXFjM1c0c20zNVlRSC1hQi5DNUEzOUFFNkIyOUUzOTRC). The latter includes the information about which playlist the video is in. That's why you don't need to specify the playlistId when deleting a video from a playlist, just this one long videoId.
This is the videoId NOT to use when deleting a video from your playlist:
youtube.playlistItems().list("contentDetails,snippet").execute().items[0].snippet.resourceId.videoId
And this is the videoId to use:
youtube.playlistItems().list("contentDetails,snippet").execute().items[0].id

Access Google spreadsheet API without auth token

I have created Google Spreadsheet, and given edit access to all (can edit even without login).
Here is the link. I would like to update this sheet with Google Spreadsheet API. But I am getting error. My requirement is update the sheet thru API even without access credential.
It is possible to write to spreadsheet without OAuth or API Keys. You need to use Service Account Keys.
Here is what I did for my Node.js environment.
Get a service account key from https://console.cloud.google.com/apis/credentials (You can here also restrict what this keys is allowed todo)
When creating, make sure you click the Furnish a new private key
Select JSON when it asks you how to download the key.
The service account key you have just generated includes a client_email.
Go to you google spreadsheet and allow this client_email to have write access on this document
Use the following code to authenticate
let jwtClient = new google.auth.JWT(client_email, null, private_key, [
"https://www.googleapis.com/auth/spreadsheets",
]);
//authenticate request
jwtClient.authorize(function(err, tokens) {
// at this point the authentication is done you can now use `jwtClient`
// to read or write to the spreadsheet
});
client_email and private_key are part of the service account key
A more detailed description can be found here. http://isd-soft.com/tech_blog/accessing-google-apis-using-service-account-node-js/ Also, all credit goes to this page.
You need to be authorized to make such requests
Every request your application sends to the Google Sheets API needs to
identify your application to Google. There are two ways to identify
your application: using an OAuth 2.0 token (which also authorizes the
request) and/or using the application's API key. Here's how to
determine which of those options to use:
If the request requires authorization (such as a request for an
individual's private data), then the application must provide an OAuth
2.0 token with the request. The application may also provide the API key, but it doesn't have to. If the request doesn't require
authorization (such as a request for public data), then the
application must provide either the API key or an OAuth 2.0 token, or
both—whatever option is most convenient for you.
That's it. There's no bypassing authorization.
Finally digged deep enough and found the answer. Any kind of writing, even to publicly editable sheets requires an OAuth flow:
https://issuetracker.google.com/issues/36755576#comment3
Jürgen Brandstetter's answer above is completely right. Using Postman, I have been successful without using an OAuth token (I needed my personal API key and a service account) - I have written to a new sheet (in fact I did a batchUpdate operation with two steps, first create a new sheet and then pasteData on it). I followed the instructions here to create a service account, downloaded the credentials JSON and used it to create and sign a JWT string that is later used as Bearer.
Here is the Java code to obtain the JWT string:
private static String getSignedJWT() throws IOException {
InputStream in = YourClass.class.getResourceAsStream("/downloaded-service-account-creds.json");
if (in == null) {
throw new FileNotFoundException("Resource not found");
}
ServiceAccountCredentials serviceAccountCredentials = ServiceAccountCredentials.fromStream(in);
GoogleCredentials googleCredentials = serviceAccountCredentials
.createScoped(Collections.singletonList(SheetsScopes.SPREADSHEETS));
PrivateKey privateKey = serviceAccountCredentials.getPrivateKey();
String privateKeyId = serviceAccountCredentials.getPrivateKeyId();
long now = System.currentTimeMillis();
Algorithm algorithm = Algorithm.RSA256(null, (RSAPrivateKey)privateKey);
String signedJwt = JWT.create()
.withKeyId(privateKeyId)
.withIssuer(serviceAccountCredentials.getClientEmail())
.withSubject(serviceAccountCredentials.getClientEmail())
.withAudience("https://sheets.googleapis.com/")
.withIssuedAt(new Date(now))
.withExpiresAt(new Date(now + 3600 * 1000L))
.sign(algorithm);
return signedJwt;
}
Dependencies needed: com.auth0:java-jwt and com.google.auth:google-auth-library-oauth2-http.
Here's the curl that uses the JWT string generated above:
curl --location --request POST 'https://sheets.googleapis.com/v4/spreadsheets/YOUR_SHEET_ID:batchUpdate?key=ANY_PERSONAL_API_KEY' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_JWT_STRING' \
--data-raw '{
"requests": [
{
"addSheet": {
"properties": {
"title": "newPred",
"sheetId": 0
}
}
},
{
"pasteData": {
"coordinate": {
"columnIndex": 0,
"rowIndex": 0,
"sheetId": 0
},
"delimiter": "\t",
"data": "col1\tcol2\nPeter\t25",
"type": "PASTE_NORMAL"
}
}
]
}'
Not exactly what asked but here is a solution with google-api-nodejs-client worked for me:
const { google } = require('googleapis');
const sheets = google.sheets('v4');
const spreadsheetId = '.........';
(async () => {
const auth = new google.auth.GoogleAuth({
keyFile: './my_service_account_privatekey.json',
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
});
// get
try {
const getResult = await sheets.spreadsheets.values.get({
auth,
spreadsheetId,
range: 'Sheet1!B2:C4'
})
console.log('Got values:', getResult.data.values)
} catch (error) {
console.error('Get error:', error)
}
})()
docs: https://github.com/googleapis/google-api-nodejs-client#using-the-keyfile-property

Youtube Data API V3 - Unable to fetch mostPopular youtube videos from android app with restricted API key

In my Android app, I am trying to fetch the most popular youtube videos for a particular region using Youtube Data API V3, which does not require OAuth.
But getting the below exception :
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403
Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "The request did not specify any Android package name or signing-certificate fingerprint. Please ensure that the client is
sending them or use the API Console to update your key restrictions.",
"reason" : "ipRefererBlocked",
"extendedHelp" : "https://console.developers.google.com/apis/credentials?project=653745488165"
} ],
"message" : "The request did not specify any Android package name or signing-certificate fingerprint. Please ensure that the client is
sending them or use the API Console to update your key restrictions."
}
I could not find any API to send or attach package name or signing-certificate fingerprint with the request.
I generated the API key for my android application in google developer console and resticted the API key to my app by specifying
the package name of my app and SHA-1 fingerprint of my apk's keystore file.
Code snippet used to fetch mostPopular videos :
sYoutube = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) throws IOException {
}
}).setApplicationName(/*package name of my application here*/>).build();
list = sYoutube.videos().list("snippet,contentDetails");
list.setChart("mostPopular");
list.setMaxResults(3);
list.setRegionCode("IN");
list.setKey(/*API key generated in google developers console*/);
VideoListResponse response = list.execute();
But if I remove the restrictions of the API key,I am able to fetch the videos without any error. But I dont want to remove the
API key restrictions.
Thank you very much in advance for any help.

OAuth 2.0 with Google Analytics API v3

I used to be able to query the Google Analytics API with my account's login & password.
Google is now using OAuth for authentication which is great...
The only issue is that I only need ONE access token.
I don't wanna allow other users to fetch THEIR analytics data.
I just wanna be able to fetch MY data.
Is there a way I can generate an access token only for my app or my analytics account?
I know such solutions exists... For instance, Twitter provides what they call a "single-user oauth" for apps that don't require a specific user to sign in.
One again, all I'm trying to accomplish here is to fetch MY OWN analytics data via the API.
Is there a way to properly do that?
I'm adding a PHP answer - you may be able to adjust or convert it to garb / ruby code.
You should be able to use Analytics with service accounts now. You will indeed have to use a private key instead of an access token.
Create an app in the API Console
Basically, you go to the Google API Console and create an App.
Enable Google Analytics in the services tab.
In the API Access tab, create a new OAuth ID (Create another client ID... button), select service account and download your private key (Generate new key... link). You'll have to upload the key to your web server later.
On the API Access page, in the Service account section, copy the email address (#developer.gserviceaccount.com) and add a new user with this email address to your Google Analytics profile. If you do not do this, you'll get some nice errors
Code
Download the latest Google PHP Client off SVN (from the command line svn checkout http://google-api-php-client.googlecode.com/svn/trunk/ google-api-php-client-read-only).
You can now access the Analytics API in code:
require_once 'Google_Client.php';
require_once 'contrib/Google_AnalyticsService.php';
$keyfile = 'dsdfdss0sdfsdsdfsdf44923dfs9023-privatekey.p12';
// Initialise the Google Client object
$client = new Google_Client();
$client->setApplicationName('Your product name');
$client->setAssertionCredentials(
new Google_AssertionCredentials(
'11122233344#developer.gserviceaccount.com',
array('https://www.googleapis.com/auth/analytics.readonly'),
file_get_contents($keyfile)
)
);
// Get this from the Google Console, API Access page
$client->setClientId('11122233344.apps.googleusercontent.com');
$client->setAccessType('offline_access');
$analytics = new Google_AnalyticsService($client);
// We have finished setting up the connection,
// now get some data and output the number of visits this week.
// Your analytics profile id. (Admin -> Profile Settings -> Profile ID)
$analytics_id = 'ga:1234';
$lastWeek = date('Y-m-d', strtotime('-1 week'));
$today = date('Y-m-d');
try {
$results = $analytics->data_ga->get($analytics_id,
$lastWeek,
$today,'ga:visits');
echo '<b>Number of visits this week:</b> ';
echo $results['totalsForAllResults']['ga:visits'];
} catch(Exception $e) {
echo 'There was an error : - ' . $e->getMessage();
}
Terry Seidler answered this nicely for php. I want to add a java code example.
Api console setup
Start by doing the required steps in the google api console as Terry explained:
Basically, you go to the Google API Console and create an App. Enable
Google Analytics in the services tab. In the API Access tab, create a
new OAuth ID (Create another client ID... button), select service
account and download your private key (Generate new key... link).
You'll have to upload the key to your web server later.
On the API Access page, in the Service account section, copy the email
address (#developer.gserviceaccount.com) and add a new user with this
email address to your Google Analytics profile. If you do not do this,
you'll get some nice errors
Get the necessary libraries
Download the google analytics java client from:
https://developers.google.com/api-client-library/java/apis/analytics/v3
Or add the following maven dependencies:
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-analytics</artifactId>
<version>v3-rev94-1.18.0-rc</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson</artifactId>
<version>1.18.0-rc</version>
</dependency>
Now for the code:
public class HellowAnalyticsV3Api {
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
public void analyticsExample() {
// This is the .p12 file you got from the google api console by clicking generate new key
File analyticsKeyFile = new File(<p12FilePath>);
// This is the service account email address that you can find in the api console
String apiEmail = <something#developer.gserviceaccount.com>;
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(apiEmail)
.setServiceAccountScopes(Arrays.asList(AnalyticsScopes.ANALYTICS_READONLY))
.setServiceAccountPrivateKeyFromP12File(analyticsPrivateKeyFile).build();
Analytics analyticsService = new Analytics.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(<your application name>)
.build();
String startDate = "2014-01-03";
String endDate = "2014-03-03";
String mertrics = "ga:sessions,ga:timeOnPage";
// Use the analytics object build a query
Get get = analyticsService.data().ga().get(tableId, startDate, endDate, mertrics);
get.setDimensions("ga:city");
get.setFilters("ga:country==Canada");
get.setSort("-ga:sessions");
// Run the query
GaData data = get.execute();
// Do something with the data
if (data.getRows() != null) {
for (List<String> row : data.getRows()) {
System.out.println(row);
}
}
}
You can use a refresh token. Store the refresh token in a db or secure config file, then use it to show the stats.
Google API Offline Access Using OAuth 2.0 Refresh Token will give you an idea of how to capture then store your refresh token.
See also Using OAuth 2.0 for Web Server Applications - Offline Access
Hello I found a solution, it works for me
you have to change this one
immediate: true
to
immediate: false
and it looks like
function checkAuth() {
gapi.auth.authorize({
client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
}
Google has the 'Service Account' (Calls Google APIs on behalf of your application instead of an end-user), but the way it works is a bit different as it won't use access tokens but a private key instead.
You can find more details at https://developers.google.com/accounts/docs/OAuth2ServiceAccount

Resources