SoundCloud API 403 Search Endpoint - javascript

I am wanting to make use of the SoundCloud API so a user can search for an artist and then click their tracks to get an embed code.
I am using the SDK and the embed function works fine as follows:
SC.initialize({
client_id: 'XXXXXXX'
});
var track_url = 'https://soundcloud.com/forss/flickermood';
SC.oEmbed(track_url, { auto_play: true }).then(function(oEmbed) {
console.log('oEmbed response: ', oEmbed);
});
But when I use the search endpoint I get 403.
SC.get('/tracks', {
q: 'buskers', license: 'cc-by-sa'
}).then(function(tracks) {
console.log(tracks);
});
I noticed that SoundCloud uses a v2 api for the search on their site - is this documented anywhere?
I haven't been able to register an app and I have seen it's been closed for a while - I'm wondering what I need to do to get past this 403 and if it's because my client_id which I grabbed from my browser.
Any insight would be great - the API looks fairly extensive but void if I can't use it.

Related

Creating a YouTube playlist with React using Google's API

I would like to create a YouTube playlist on a users account, but I have struggled to authenticate a POST to the YouTube v3 api.
I'll start by showing how far I have got with this problem.
YouTube API Documentation
The Youtube API Documentation provides details on creating a playlist, and has a working example in the API Explorer
I entered the following code into the request body:
{
"snippet":
{
"title":"Test Playlist"
}
}
This successfully created a playlist on my YouTube account with the same title. So from this I could tell that, a title was required within the body and it would require OAuth 2.0 authentication (an error is displayed if it is not enabled) using one the scopes: youtube, youtube.force-ssl, youtubepartner.
First attempt in react
The First thing I tried was similar to this:
fetch('/youtube/v3/playlists', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer' + api.youtube,
},
body: JSON.stringify({
"snippet":
{
"title":"Test"
}
})
}).then(response => response.json()).then(data => {
console.log(data)
})
api.youtube contains my YouTube api key.
Most of the formatting for this came from another API I have in the same program for getting data from spotify which works.
The response I got from this would say "Login failed" or "Authentication Error" (something along those lines)
Anyway, this is relevant because I know that my first hurdle is getting authentication.
Authentication
The YouTube API Documentation contains a guide titled Implementing OAuth 2.0 Authorization I followed the guide for client side web apps.
The first thing I noticed is that they are using a library, I found this on npm under googleapis and installed it.
When I tried to call this in React using
const {google} = require('googleapis');
I won't get deep into the error but react said "Can't convert undefined to object" and found an issue which said that googleapis is intended for server side not client side, I tried building the react app and putting it on herokuapp but got the same error. Someone else suggested using gapi-client on npm which is a node wrapper for googleapis.
The next thing I did was try the example on the npm page, which is very similar to the google example for configuring the client object. I have it so the import part and function are at the top of my app.js and then the gapi.load part activates after a button is pressed (this could be useless info but w/e)
import gapi from 'gapi-client';
//On load, called to load the auth2 library and API client library.
gapi.load('client:auth2', initClient);
function initClient() {
gapi.client.init({
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"],
clientId: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/drive.metadata.readonly'
}).then(function () {
// do stuff with loaded APIs
console.log('it worked');
});
}
I copied my client ID in from the API Console and this is the exact response I got:
FireFox
Loading failed for the with source
“https://apis.google.com//scs/apps-static//js/k=oz.gapi.en.WcpMzqgmJZU.O/m=auth2,client/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCNsTS1p4dx0iMhlrwEpiaXw4iMjOg/cb=gapi.loaded_0”.
Chrome
GET
https://apis.google.com//scs/apps-static//js/k=oz.gapi.en.WcpMzqgmJZU.O/m=auth2,client/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCNsTS1p4dx0iMhlrwEpiaXw4iMjOg/cb=gapi.loaded_0
net::ERR_ABORTED 404
That's about as far as I got and I'm not sure what to do from here, so any help is much appreciated. I hope this didn't get too convoluted but I've tried to convey my problem as clearly as possible.
So I was able to authorize the YouTube API and create a playlist.
I have a backend hosted on localhost:8888 (doesn't matter just not what react is hosted on).
here is sample code for what I put in the server.js file (for the backend)
var express = require('express');
var app = express();
var passport = require('passport');
app.use(passport.initialize());
var YoutubeV3Strategy = require('passport-youtube-v3').Strategy;
passport.use(new YoutubeV3Strategy({
clientID: YOUR_CLIENT_ID,
clientSecret: YOUR_CLIENT_SECRET,
callbackURL: 'http://localhost:8888/redirect',
scope: ['https://www.googleapis.com/auth/youtube']
},
function (accessToken, refreshToken, profile, cb) {
var user = {
accessToken: accessToken,
refreshToken: refreshToken
};
return cb(null, user)
}
));
passport.serializeUser(function(user, cb) {
cb(null, user);
});
passport.deserializeUser(function(obj, cb) {
cb(null, obj);
});
app.get('/authenticate', passport.authenticate('youtube'))
app.get('/redirect', passport.authenticate('youtube', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('http://localhost:3000' + '?access_token=' + req.user.accessToken)
})
app.listen(8888)
This is using Passport.js to do oauth for me, lots of documentation can be found on the site.
In react I have it so a button will open localhost:8888/authenticate and then that will redirect back to my application. If you are using this you need to make sure that on your google API credentials you have the javascript origin as http://localhost:8888 and the redirect URI as http://localhost:8888/redirect and the correct scope and application type.
This is the function I use in my app.js (react) to make the POST
getAPIdata() {
let parsed = queryString.parse(window.location.search);
let accessToken = parsed.access_token
fetch('https://www.googleapis.com/youtube/v3/playlists?part=snippet', {
method: 'POST',
headers: {
'Content-type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
},
body: JSON.stringify({
'snippet':
{
'title':this.state.inputTitle
}
})
}).then(response => response.json()).then(data => {
console.log(data)
window.alert('https://www.youtube.com/playlist?list=' + data.id)
})
}
I was actually mostly correct with the first attempt I just had the authorization incorrect.
Here's a couple sources that helped me make my solution:
Passport.js oauth tutorial
Googles OAuth 2.0 Playground
Passport.js Documentation
Passport.js facebook oauth example
Hopefully this is helpful to someone, You can use the same code i used in server.js to authenticate most services by just changing the strategy.
A live version of my application can be found here. In the console it shows the response from the POST request, this should help if you have any issues. I know the alert is bad ui but this wasn't the intended use.
Thanks for reading :)

Facebook Javascript SDK: Can't load a page's public feed [duplicate]

I'm trying to use the Facebook Graph API to get the latest status from a public page, let's say http://www.facebook.com/microsoft
According to http://developers.facebook.com/tools/explorer/?method=GET&path=microsoft%2Fstatuses - I need an access token. As the Microsoft page is 'public', is this definitely the case? Is there no way for me to access these public status' without an access token?
If this is the case, how is the correct method of creating an access token for my website? I have an App ID, however all of the examples at http://developers.facebook.com/docs/authentication/ describe handling user login. I simply want to get the latest status update on the Microsoft page and display it on my site.
This is by design. Once it was possible to fetch the latest status from a public page without access token. That was changed in order to block unidentified anonymous access to the API. You can get an access token for the application (if you don't have a Facebook application set for your website - you should create it) with the following call using graph API:
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID&client_secret=YOUR_APP_SECRET&
grant_type=client_credentials
This is called App Access Token. Then you proceed with the actual API call using the app access token from above.
hope this helps
You can use AppID and Secret key to get the public posts/feed of any page. This way you don't need to get the access-token. Call it like below.
https://graph.facebook.com/PAGE-ID/feed?access_token=APP-ID|APP-SECRET
And to get posts.
https://graph.facebook.com/PAGE-ID/posts?access_token=APP-ID|APP-SECRET
It's no more possible to use Facebook Graph API without access token for reading public page statuses, what is called Page Public Content Access in Facebook API permissions. Access token even is not enough. You have to use appsecret_proof along with the access token in order to validate that you are the legitimate user. https://developers.facebook.com/blog/post/v2/2018/12/10/verification-for-individual-developers/.
If you are individual developer, you have access to three pages of the data (limited), unless you own a business app.
You can get the posts by simply requesting the site that your browser would request and then extracting the posts from the HTML.
In NodeJS you can do it like this:
// npm i request cheerio request-promise-native
const rp = require('request-promise-native'); // requires installation of `request`
const cheerio = require('cheerio');
function GetFbPosts(pageUrl) {
const requestOptions = {
url: pageUrl,
headers: {
'User-Agent': 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0'
}
};
return rp.get(requestOptions).then( postsHtml => {
const $ = cheerio.load(postsHtml);
const timeLinePostEls = $('.userContent').map((i,el)=>$(el)).get();
const posts = timeLinePostEls.map(post=>{
return {
message: post.html(),
created_at: post.parents('.userContentWrapper').find('.timestampContent').html()
}
});
return posts;
});
}
GetFbPosts('https://www.facebook.com/pg/officialstackoverflow/posts/').then(posts=>{
// Log all posts
for (const post of posts) {
console.log(post.created_at, post.message);
}
});
For more information and an example of how to retrieve more than 20 posts see: https://stackoverflow.com/a/54267937/2879085
I had a similar use case for some weeks and I used this API:
https://rapidapi.com/axesso/api/axesso-facebook-data-service/
I could fetch all posts and comments in some minutes, worked quite well for me.

OAuth 2.0 authentication silently failing in Google Blogger JavaScript API (v3)

Until recently I was using the javascript Blogger API v3 to fetch posts from a blog to build an automated index, using the gapi.client.blogger.posts.list() method.
However, it suddenly stopped working. The response now simply includes an error object with the message "We're sorry, but the requested resource could not be found.", as if the blog I'm trying to fetch info does not exist at all. I'm pretty sure my blog ID did not change during my sleep.
So I started digging around, and I found that the OAuth authentication token returned says I'm not actually logged in Google. In the status object from the token, the signed_in property is true but the google_logged_in one is false. Yet the Google login page showed up correctly upon execution and I allowed it, and the token does not have an error property. Why does it says I'm not logged in?
I'm under the assumption that Google blocked my application from making new requests due repeated use (even thought I never reached a dent of the daily quota) and now since the OAuth 2 ID authentication does not work, the API tries to use only the web browser API key, which does not work either since it's a private blog and user permission is required. But I really don't know.
I could not find a similar situation on the internet. I tried deleting both my API and OAuth keys and making new ones, deleting the project from the Google Console Developers and creating a new one under a different account, removing the application from the "allowed apps" in my account and adding it again, not using the browser API key. No game.
I would appreciate any inputs in solving this issue. And before anyone suggests: the "conventional" way of creating an automated index using the blog's feed does not work in my case, since the blog is private and has no feed.
Bellow is the returned access token (redacted a bit):
{
_aa: "1"
access_token: "[Redacted]"
client_id: "[Redacted]"
cookie_policy: undefined
expires_at: "1460999668"
expires_in: "3600"
g_user_cookie_policy: undefined
issued_at: "1460996068"
response_type: "token"
scope: "https://www.googleapis.com/auth/blogger.readonly"
state: ""
status: {
google_logged_in: false
method: "AUTO"
signed_in: true
}
token_type: "Bearer"
}
And bellow an example code of my application:
var apiKey = "myWebBrowserApiKey";
var clientId = "myOAuth2ClientID";
var blogId = "myBlogID";
var bloggerReadOnly = "https://www.googleapis.com/auth/blogger.readonly";
var fetchParam = {
blogId: blogId,
fetchBodies: false,
fetchImages: false,
maxResults: 500,
status: "live",
view: "READER"
};
var authParamIm = {
client_id: clientId,
scope: bloggerReadOnly,
immediate: true
};
var authParam = {
client_id: clientId,
scope: bloggerReadOnly,
immediate: false
};
//Executed as soon the client:blogger.js loads
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
//Check if the user is already authenticated for immediate access
function checkAuth() {
gapi.auth.authorize( authParamIm, handleAuthResult );
}
function handleAuthResult(authResult) {
//If the user does already have authorization, proceed with the API call
if (authResult && !authResult.error) {
makeApiCall();
}
//If he does not, shows the authorization button
else {
authorizeButton.css('visibility', 'visible');
authorizeButton.click(handleAuthClick);
}
}
//The authorization button calls this function, that shows a Google login page
function handleAuthClick(event) {
gapi.auth.authorize( authParam, handleAuthResult );
return false;
}
//Loads the Blogger API, version 3, and runs the fetchPosts() function with a callback
function makeApiCall(){
gapi.client.load('blogger', 'v3', fetchPosts);
}
function fetchPosts(){
//Creates a request to get a list of posts from the blog, using the fetch parameters
var request = gapi.client.blogger.posts.list(fetchParam);
//Execute the request and treats the response with a callback function
request.execute(function(response){
//Do Stuff
}
}

Login using facebook get username, email

I am using login using facebook in my website,
Here is the button
<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>
I am using the exact example given here
But after the check login status, i am getting the response with only the userid of facebook and token, but i want to get the username too.. How can i get that ?
Help pls
Here is the script
window.fbAsyncInit = function () {
FB.init({
appId: 'xxxx',
cookie: true, // enable cookies to allow the server to access
// the session
xfbml: true, // parse social plugins on this page
version: 'v2.2' // use version 2.2
});
FB.getLoginStatus(function (response) {
console.log(response);
console.log(response.email);
//here status is connected
//statusChangeCallback(response);
});
};
In the resopnse, i am getting the entire json,
In the response.status i am getting as connected
But while i try response.email i am getting undefined
How can i get the email or username ?
EDITED to show what actually fixed it for me:
So it does appear to depend on what version of the API your config is set to allow. BUT, I was able to get the email address on a v2.5 api by using the following:
If you are using the Hello World code, then replace this section:
FB.api('/me', function (response) {
console.log('Success ');
console.log(response);
});
With this:
FB.api('/me', { fields: 'email' }, function (response) {
console.log('Success ');
console.log(response);
});
The difference is adding the { fields: 'email' } object to the call. This appears to have been a new addition in either v2.4 or v2.5 of the API which is why older code you see on SO appears to work for the poster but not for you. Hope this helps.
I'm not sure this qualifies as a solution, but I was able to reproduce this issue (no email returned after a valid request).
I have two apps, each created under a different FB account. The first one was created more than a year ago and the second one was created today. I have code that runs perfectly against the older app (returns email) and fails against the newer app (no email).
At first I thought maybe FB just holds back on certain data for brand new apps but I thought it was odd that it wouldnt be documented anywhere.
So I decided to compare each app configuration side by side. I found that the older one had API VERSION (at the top of the dashboard) set to 2.0 and the newer was 2.5. The Hello World code on the API SDK page requests version 2.2 like so:
window.fbAsyncInit = function () {
FB.init({
appId: [my app id here],
cookie: true, // enable cookies to allow the server to access
// the session
xfbml: true, // parse social plugins on this page
version: 'v2.2'
})
};
According to the documentation, the fact that the newer app has API set to 2.5 in the config means that any requests for an older API (eg 2.2) will be automatically upgraded to 2.5. When I set the javascript above to request 2.5 (eg version: 'v2.5'), I was able to get the older app to fail too. So I suspect the issue is with the newer v2.5 api.
I have not been able to find out how to set my new app to accept older api calls but will update here if I do.

Youtube Data API and Google Cloud Endpoints

I'm having issues getting Google cloud endpoints working in tandem with the YouTube data API v3 in my javascript client. I think my issue is around the gapi.client.setApiKey() method setting the key for both my endpoints API and the YouTube api. When I do set the key YouTube works but my endpoints do not and I see the following error using my endpoints API:
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured. The API () is not enabled for your project. Please use the Google
Developers Console to update your configuration.",
"extendedHelp": "https://console.developers.google.com"
}
Without the key my endpoints work but youtube search does not and I get this message using the search feature:
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
The code that loads the API is summarised below but essentially I have followed the endpoints python/javascript tutorial and the youtube data API tutorials!
init = function(apiRoot) {
var apisToLoad;
var callback = function(){
if(--apisToLoad == 0){
enableButtons();
}
}
apisToLoad = 2; // must match number of calls to gapi.client.load()
gapi.client.load('myAPIName', 'v1', callback, apiRoot);
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
};
// Called automatically when YouTube API interface is loaded (see line 9).
function onYouTubeApiLoad() {
//sets the api key
gapi.client.setApiKey('APIKeyForYouTubeFromDevConsole');
}
To verify only the youtube API requests with the API key remove the api.client.setApiKey method call.
In calls to the YouTube data API add a key parameter to the API request:
var request = gapi.client.youtube.search.list({
part: 'snippet',
type: 'video',
maxResults: 12,
q: searchValue,
key: 'YourAPIKeyGoesHere'
});
This means only these API calls are authorised and not the endpoints calls.
I'm not extremely familiar with the Youtube Data API. But I recognize the code you used for your Endpoints as the code that we provide. You can definitely use this code for the Endpoints API. For the Youtube Data one, I suggest looking here.
Looks like the code you need would be something like this :
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.services.youtube.YouTube;
public class myClass {
/**
* Define a global instance of a Youtube object, which will be used
* to make YouTube Data API requests.
*/
private static YouTube youtube;
public static void main(String[] args) {
List<String> scopes = Lists.newArrayList("https://www.googleapis.com/auth/youtube");
try {
// Authorize the request.
Credential credential = Auth.authorize(scopes, "invideoprogramming");
// This object is used to make YouTube Data API requests.
youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential)
.setApplicationName([YOUR APP])
.build();
}
From there you should be able to use the youtube object to make your calls, and the gapi to send stuff to your endpoint.

Categories

Resources