Given the new Spotify web api authentication credentials, is it possible to run the api without a server? - node.js

I'm trying to run the spotify web api using node-spotify-api npm package. In order to require the package I have to use something called browserify, which allows me to specifically use the "require()" function in the browser. I'm strictly trying to run the api on the client side. When I do, this is the error I get -
// I have my client ID and client secret ID delcared in variables
// Code below is suppose to execute the search function once the user enters a track
var query = $("#query").val().trim();
console.log(query)
spotify.search({ type: 'track', query: query }, function(err, data)
{
if (err) {
return console.log('Error occurred: ' + err);
}
console.log(data);
});
// Once executed, I get the error below
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access. If an opaque
response serves your needs, set the request's mode to 'no-cors' to
fetch the resource with CORS disabled.
bundle.js:120 Error occurred: RequestError: TypeError: Failed to fetch
I looked up the error and everything I'm looking at redirects me in the direction of running the api on the server side which I do not want to do if possible. Any thoughts on how to strictly run this client-side?

I think you are describing the auth flow called Client Credentials, and no, this is not possible because Spotify refuses to allow CORS on their auth token endpoint. See this issue on GitHub.
You will need to use the Implicit Grant flow to utilize the API entirely within the browser.

Related

authentication header vs query parameter in google cloud endpoints

I have tried everything, yet I cannot access my API using google cloud endpoints using a Authentication:Bearer header. According to Cloud Endpoints Docs:
When you send a request using an authentication token, for security reasons, we recommend that you put the token in the Authorization:Bearer header.
it also says:
If you cannot use the header when sending the request, you can put the authentication token in a query parameter called access_token.
I can perfectly access the API using access_token=" +idToken in my URL. However, when I try to send an HTTP request with the Authentication header like this:
const url =
"https://<PROJECTNAME>.appspot.com/getbalance";
axios
.get(url,{headers:{'Authentication':'Bearer '+idToken}})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
I get this error:
JWT validation failed: Missing or invalid credentials
Is sending the token in a query parameter as safe as sending it in the header?
Your code example shows you setting an Authentication header, not an Authorization header. You should not typically use a query parameter as it will likely get logged in Cloud Console.
When using "Authorization: Bearer ", you would need to use an access token obtained through OAuth 2.0 authentication.
This can be illustrated if you use the Oauth Playground agains any of the Google APIs.
Keep in mind that if you want to access your Firebase database using the Oauth Playground, you would need to configure the client ID and client Secret of your Firebase project on the gear icon at the top right of the playground screen.
Also make sure to use these scopes:
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/firebase.database
After completing all the steps, you will be able to make a REST request using the authorization header with the obtained access token.

Microsoft login from oauth2 issue

I have a React app using axios library for handling request. So following the next post:
How to login with username/password using OAuth2 and microsoft login and HTTP request
I could perform the action on Postman.
Then I set up the axios library to perform the POST
const dataForBody = `${'grant_type=password&' +
'username='}${encodeURI(userName)}&` +
`password=${encodeURI(userPassword)}&` +
`client_id=${encodeURI(clientID)}&` +
`resource=${encodeURI('https://graph.microsoft.com')}&` +
`client_secret=${encodeURI(clientSecret)}`;
const messageHeaders = {
'Content-Type': 'application/x-www-form-urlencoded'
};
axios({
method: 'post',
url: 'https://login.microsoftonline.com/{tenant}/oauth2/token',
headers: messageHeaders,
data: dataForBody,
})
.then((response) => {
});
but I get the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at
https://login.microsoftonline.com/{tenant}/oauth2/token.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
I tried adding:
'Access-Control-Allow-Origin': 'https://login.microsoftonline.com',
to the headers, but it did not work.
So adding Allow-Control-Allow-Origin: *​​​ chrome extension fixed my problem.
The thing is, my app is to be published on azure, so I tested the request on other web browsers and it did not work. So I don't want my users to install the extension.
Is there something wrong with my request? Why postman can do it without setting up headers?
Is there any other approach to achieve it?
PS: I read about using adal.js but I dont want to use the login screen from microsoft, because I know user and pass for the app, and I want to avoid manual login.
The problem you face is due to you trying to call the token endpoint via AJAX, which it won't accept due to the CORS header missing. You can't add it, it's missing from the response from Azure AD.
What you need to do is instead of getting the access token from the token endpoint, you must use the OAuth Implicit Grant Flow. This flow allows you to get the tokens directly in the authorization stage, and is especially designed for JavaScript-based apps. More info here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-dev-understanding-oauth2-implicit-grant.
What this means is that you can't use the Password Grant Flow as you are doing now, unless you make the calls from your backend instead of the frontend.

Live Paypal Application fails to create token information from auth code but not in sandbox

In my Meteor web application I have managed to successfully implement some functions that allow me to take an authorization code granted from Paypal's authorizeUrl function via the RESTful Paypal Node SDK in the Sandbox in order to assign a refresh token to an existing user. However, now that we need to deploy it to a Live environment, we are running into problems because the Paypal API is complaining with the following error:
Error: Response Status: 400
This means the request was bad, due perhaps to a 'bad syntax.' However, I am using the correct live API credentials and the authorization URL endpoint is the correct one at https://www.paypal.com/signin/authorize
Unfortunately this bug doesn't occur when I am reverting back to my sandbox mode configuration.
As a follow up, trying to pass an invalid authorization code to my sandbox configuration endpoint provides me the appropriate error message 400 with Invalid authorization code whereas the live environment gives me no such help...
The latest paypal-debug-id I have on hand is 83d570f17357e
EDIT:
It turns out Paypal thinks client id or secret is null even though I have clearly provided the configuration with client_id, client_secret, openid_client_id and openid_client_secret. This confuses me even more
EDIT 2:
Using the same Live API credentials I can successfully set up a basic payment flow using the Rest SDK, but I cannot use open ID connect with the same client ID and secret. Maybe that has something to do with it?
After some extensive testing and wrestling with the API it was discovered that there was actually a configuration conflict going on when binding the Meteor.wrapAsync API call to an instance of paypal created from the node SDK.
Assuming my Meteor.wrapAsync call is this:
var wrapGetUserInfo = Meteor.wrapAsync(openIdCxn.userinfo.get.bind(openIdCxn.userinfo), function (err, userinfo) {
if (err) {
console.log(err);
throw new Meteor.Error(500, "Internal Server Error", err);
}
});
Then instead of doing
var userInfo = wrapGetUserInfo(returnObject.access_token, paypal);
I will do
var userInfo = wrapGetUserInfo(returnObject.access_token);
And then it no longer complains

Node POST request not working for Instagram API: This client has not been approved to access this resource

I'm trying to do some simple GET/POST requests with Instagram's API. I have a get request that uses the request node module and it works fine. I have an access token attached to the end of my query https://api.instagram.com/v1/users/[user]/media/recent?[access_token]
request(
{url, method: "GET"}, function(error, response, body) {
var parsed = JSON.parse(body)
console.log(parsed.data[5])
});
However, when I try to make a post request in postman with the following query:
https://api.instagram.com/v1/media/[media-id]/likes?[authID]
it displays
{"meta":
{"error_type":"OAuthPermissionsException","code":400,"error_message":"This
client has not been approved to access this resource."}}
I'm in sandbox mode and the docs specify that you can do up to 30 POST req's to an endpoint an hour with no live account. Can anybody shed some light on this?
What kind of scopes you have requested for this token? Your GET request requires just public_content permission, while POST likes requires likes scope. You should add this permission to scope list during authorization.

How to programmatically login to Facebook oauth2 api

Background:
I have written a Node.JS script that successfully connects to the Facebook Graph API through my facebook app. I can read data when I give it an oauth access_token, I want this script to run on my server every night to store some data. I have done a lot of research of both the facebook api, oauth and similar questions on stack overflow. I am searching the /search/?type=event&q=query endpoint
Problem:
However, Facebook returns a 60 day access_token through the oauth2 login process that required me to create an express server that simply initiates the oauth2 process, allows the user to login, and receives the access_token code and I am storing it.
I want the script to save data so that my server can provide access to updated data every day. I don't want to have to remember to login to generate the key once every 60 days.
Question:
Is there anyway to receive a oauth2 access_token without setting up an http or express server?
More importantly, how do I get the access_token without manually having to running that server every ~60 days.
Code:
The Module I am using requires the access_token and client_secret
fs.readFile('./facebookAuthServer/oauth.txt', function read(err, data) {
if (err) {
throw err;
}
fbNode.setAuthorization({token: data, clientSecret: authSettings.clientSecret});
// Use the auth for next call
fbNode.fetchItems(displayItems);
});
Is there some way to spoof headers? or could I use a short lived access token and refresh it? Anyway to refresh a 60 day token? Has anyone created a server side implementation of Oauth2 that does not require visiting the FB login more than the first time?
Here is how you can refresh your own access token using Grant and request.
First you need an OAuth client server up and running:
var express = require('express')
var session = require('express-session')
var Grant = require('grant-express')
var grant = new Grant({
server:{host:'dummy.com:3000', protocol:'http'},
facebook:{
key:'[APP_ID]',
secret:'[APP_SECRET]',
scope:['user_about_me','user_birthday'],
callback:'/callback'
}
})
var app = express()
app.use(session({secret:'very secret'}))
app.use(grant)
app.get('/callback', function (req, res) {
res.end(JSON.stringify(req.query))
})
app.listen(3000, function () {
console.log('Oh Hi', 3000)
})
Next you need an HTTP client that will simulate the browser request:
var request = require('request')
request.get({
uri:'http://dummy.com:3000/connect/facebook',
headers:{
'user-agent':'Mozilla/5.0 ...',
cookie:'datr=...; lu=...; p=-2; c_user=...; fr=...; xs=...; ...'
},
jar:request.jar(),
json:true
}, function (err, res, body) {
if (err) console.log(err)
console.log(body)
})
How you use it:
Register OAuth app on Facebook and set your Site URL (I'm assuming http://dummy.com:3000)
Add 127.0.0.1 dummy.com to your hosts file
Configure and start the server from above
Navigate to dummy.com:3000 in your browser
Open up the Developer Tools and navigate to the Network tab, make sure Preserve log is checked
Navigate to http://dummy.com:3000/connect/facebook and authenticate as usual
Take a look at the authorize request in the Network tab and copy the relevant headers to the HTTP client example (the user-agent and the cookie)
Run the HTTP client code (that's the code you are going to execute from time to time, the server should be running as well)
Resources:
Introduction about how to use Grant
Grant documentation
Request documentation - see the options section
Module:
I wrapped the above code into a module https://github.com/simov/facebook-refresh-token
Start with reading the docs, it's all described there, instead of guessing:
https://developers.facebook.com/docs/facebook-login/access-tokens
https://developers.facebook.com/docs/facebook-login/access-tokens#refreshtokens
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.4#login
It's somehow a pity that you don't write WHAT you want to query via the Graph API, because depending on that you could either use a non-expiring page access token or an app access token, which also doesn't have to be renewed, instead of an user access token.
There's no way to automatically extend the long-lived access token. The user must visit your app again.

Resources