Spotify API Error. 401 Permissions missing. When Attempting to Play Track - javascript

I am trying to play a track on my app using spotify-web-api-node
const playSong = async () => {
// Verify access token with
console.log(spotifyApi.getAccessToken())
setCurrentTrackId(track.track.id);
setIsPlaying(true);
spotifyApi
.play({
uris: [track.track.uri],
})
.then((d) => console.log("hi", d))
.catch((e) => console.log("err", e));
};
https://github.com/caseysiebel/spotify-clone/blob/main/components/Song.tsx#L19
When I fire off this call to spotifyApi.play(), I am getting this error back WebapiRegularError: An error occurred while communicating with Spotify's Web API. Details: Permissions missing. with error code 401.
I have the accessToken and refreshToken set in my app. I am able to log in and get data from the API such as user, playslist and track data. But when I try to play a track, it's says I don't have permission.
I thought this might have something to do with how I've set the scopes in the Spotify API, but they look correct to me.
const scopes = [
"user-read-email",
"playlist-read-private",
"playlist-read-collaborative",
"user-read-email",
"streaming",
"user-read-private",
"user-library-read",
"user-top-read",
// "user-library-modify"
"user-read-playback-state",
"user-modify-playback-state",
"user-read-currently-playing",
"user-read-recently-played",
"user-read-playback-state",
"user-follow-read",
].join(",");
https://github.com/caseysiebel/spotify-clone/blob/main/lib/spotify.ts#L5
It seems like this has something to do with the scopes passed into the authorization LOGIN_URL but the streaming scope is definitely present and I can't see what the issue. It seems this way because certain API request work and others say they don't have permission.
Does anyone see what could be causing this issue with the missing persmisions issue and the Spotify API?

In lib/spotify.ts line 23 needed to be scope: scopes, not scopes: scopes,.
Actually using type checking probably would have been helpful here.
https://github.com/currenthandle/spotify-clone/commit/736108de1a1a132c43810d8415584f3be198609a#diff-b030a1ce426906990f8ed48fd8be76f54558b94141f4c811e679fef6661d396dR23

I think the problem is with your spotify.js file.
Here in clientId are you sure the name NEXT_PUBLICCLIENT_ID is right?
Shouldn't it be NEXT_PUBLIC_CLIENT_ID.
const spotifyApi = new SpotifyWebApi({
clientId: process.env.NEXT_PUBLICCLIENT_ID,
clientSecret: process.env.NEXT_PUBLIC_CLIENT_SECERT,
});
Try and let me know if this work or not?

You need to change NEXT_PUBLIC_CLIENT_ID & NEXT_PUBLIC_CLIENT_SECRET to SPOTIFY_CLIENT_ID & SPOTIFY_CLIENT_SECRET within your [...nextauth].js, spotify.js, & .env files.
Here's the NextAuth documentation with an example:
https://next-auth.js.org/providers/spotify

Related

Inserting ACL after creating Google Room Resource frequently throws error

I have a Google Cloud function which first creates a Google Room Resource using resources.calendars.insert method from the Google admin sdk,
and right after I try to insert an ACL using Acl: insert method from the google calendar api.
Similar to the following code:
const AdminService = google.admin({version: 'directory_v1'});
try {
const response = await AdminService.resources.calendars.insert(options); // options omitted
} catch (error) {
console.log(`Google Room Resource FAIL`);
console.error(error.message);
}
await new Promise((r) => setTimeout(r, 10000));
const CalendarService = google.calendar({version: 'v3'});
try {
const res = await CalendarService.acl.insert(option); // options omitted
console.log(res);
} catch (error) {
console.log(error);
throw new Error(error.message);
}
As for the authentication, I am using a service account with the correct scopes which impersionates an admin user with the correct permissions. This is how I generate the required JWT token:
const generateJWT = async (scope:string[])=>{
const jwtClient = new google.auth.JWT(
client_email, // service account
undefined,
private_key,
scope,
subject // admin user
);
return jwtClient;
}
In the options parameter for each api call I directly acquire the token for the auth attribute like this:
const option = {
'calendarId': acl.calendarId,
'auth': await generateJWT('https://www.googleapis.com/auth/calendar'),
'resource': {
'role': acl.role,
'scope': {
'type': acl.scopeType,
'value': acl.scopeValue,
},
},
};
Since I await all api calls, I thought that I will only get the response back when everything is already propagated in Google Workspace but when I do not use the setTimeout in between I always get an Error: Not Found back.
First I had the timeout set to 5 seconds which worked until it didn't so I moved it up to 10 seconds. This worked quite long but now I get again sometimes the Not Found error back...
I don't like the setTimeout hack...and even less if it does not work reliable, so how should I deal with this asynchronous behavior without spinning up any other infrastructure like queues or similar?
Working with Google Workspace Calendar Resource
As a Super Admin on my organization when creating a Calendar Resource, from the API or the Web interface, it could take up to 24 hours to correctly propagate the information of the Calendar for the organizations, which generally affect the time it would take for any application to gather the ID of the newly created calendar, which could explain why you are increasing the time out.
You have already implemented the await option which is one of the best things you can do. You can also review the option to apply exponential back off to your application or similar to Google App Script a Utitlies.sleep().
There are multiple articles and references on how to utilize it for the retry process needed when the Resource itself has not fully propagated correctly.
You can also review the official Calendar API documentation that suggests that the error "Not Found" is a 404 error:
https://developers.google.com/calendar/api/guides/errors#404_not_found
With a suggested action of reviewing the option to set up exponential backoff to the application.
References:
GASRetry - Exponential backoff JavaScript implementation for Google Apps Script
Exponential backoff

load user.mail from Auth0 with async function

i want load the user.mail from Auth0 and safe there at a const. but I get a arrow. i don't see the error. can somebody help me to find the solution?
const userMailInfo = async () => {
auth0Client = await auth.createClient();
const result = await auth0Client.getUser().then(user => {
console.log('mail', user.email);
user.mail;
});
return result;
}
;(async () => {
const users = await userMailInfo()
console.log(users)
})()
i get follow error:
(node:19676) UnhandledPromiseRejectionWarning: ReferenceError: document is not defined
It looks like these errors are caused by code running on the server-side, where they do not have access to 'document' and the like. In SvelteKit, endpoints always run on the server, and therefore do not have access to all the elements in the 'Client API'.
To guard code from running on the server side, try calling it through OnMount(). I've linked a Sapper issue outlining some similar solutions, e.g., using if(process.browser). I am not sure if this works in SvelteKit, but may be worth checking out.
Note: It seems like the error occured outside of the provided code snippet.
SvelteKit Discord Server contains some discussions on the topic, try searching for 'UnhandledPromiseRejectionWarning ReferenceError'.
(for Sapper) https://github.com/sveltejs/sapper/issues/1226

Error: AADSTS500011: The resource principal named "URL" was not found in the tenant

I am trying to add an app to our SharePoint Online site using the template from https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part and we get the error below when we deploy to SharePoint and add the app/Web part to a test SharePoint site. We are using TypeScript as the template uses.
Has anyone else encountered this issue or know where to look for the issue?
Found [object Object]Driver Display External Error: Error: AADSTS500011: The resource principal named https://driverdisplayexternal.azurewebsites.net was not found in the tenant named 7018324c-9efd-4880-809d-b2e6bb1606b6. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant. Trace ID: 358b22eb-cd2c-4091-b592-5a57cbc21d00 Correlation ID: ec96d656-1a36-42e2-a2b9-3ff78efc1e2e Timestamp: 2019-10-01 16:26:06Z
We have added a call to our own client as shown below. We are not sure why the resource principal was not found. The Tenant ID's match and things seem to be set up properly for authentication.
HelloWorldWebPart.ts
...
this.context.aadHttpClientFactory
.getClient('https://driverdisplayexternal.azurewebsites.net')
.then((client: AadHttpClient): void => {
client
.get('https://driverdisplayexternal.azurewebsites.net/api/values', AadHttpClient.configurations.v1)
.then((response: HttpClientResponse): Promise < Order[] > => {
this.domElement.innerHTML += 'Received a response from Driver Display External: ' + response;
return response.json();
})
.catch(error => {
this.domElement.innerHTML += 'Driver Display External Error: ' + error;
console.error(error);
});
});
...
package-solution.json
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "helloworld-webpart-client-side-solution",
"id": "**ID**",
"version": "4.1.0.0",
"includeClientSideAssets": true,
"isDomainIsolated": false,
"webApiPermissionRequests": [
{
"resource": "DriverDisplayExternal",
"scope": "User.Read.All"
}
]
},
"paths": {
"zippedPackage": "solution/helloworld-webpart.sppkg"
}
}
Any help or direction to where the issue may be would be very appreciated. Thanks in advance!
Never used this API, but if I had to guess you need to change the value here:
.getClient('https://driverdisplayexternal.azurewebsites.net')
You can use either the client id / application id, or the application ID URI.
Sometimes this problem can occurr when you set a wrong name for the scope you are requesting access for or another configuration parameter.
I suggest to check carefully the scopes name, or maybe directly use the "copy" button from the Azure portal.
In my case it was a simple typo on a scope name.
Not sure if you figured the answer or not. When you used SPFx to request your own custom web api end point. there are couple steps:
request the permission so that you can go to SPO admin to approve the permission you request. for this case, the webApiPermissionRequests->resources needs to your AAD Application's Service Principal DisplayName. once you had AAD App create, you can run Get-AzureADServicePrincipal to get all your ServicePrincipal.
once you request the permission, from your code, you need to call AadHttpClient.getClient() to get aadHttpClient object based on the api resourceEndpoint you want, for this case, you need to pass your web api's Application ID URI which can be found from your AAD App's manifest->"identifierUris". General speaking, this should be something like api://[clientid] format. but you can change it to any unique value.
I hope it helps.
In my case i had to use the App Id when i was consuming a multi tenant API.
In my case, TenantId and ClientId were both ok.
They can be found in AAD. TenantId is right there on landing page:
and then on the same page click Applications then tab All Applications find your application there should be ClientId check if they match.
If that is still not enough, click on the application and find roles
For me, it was roles that were missing after adding those wheels started rolling again:

How do I save user account information to firebase?

I've made a Google Log in for my actions on google project, and I want to save the account info to a firestore database.
I looked at Google's example of how to do this (example here, at the very bottom under heading "Handle Data Access Requests"), but when you actually try to deploy it to firebase, you realize that it's actually has invalid syntax (or at least that's what the dialogflow inline editor is saying.....)
Here's what the error says specifically when I try to deploy this code:
The deployment of your Cloud Function failed:
Function load error: Code in file index.js can't be loaded.
Is there a syntax error in your code?
Detailed stack trace: /user_code/index.js:34
app.intent('Get Sign In', async (conv, params, signin) => {
^
SyntaxError: Unexpected token (
Any suggestions?
Thanks for the help!
Please note: I am using only the code that the tutorial has said to PLUS
I added the actions on google library and the fulfillment line (ie:
// Other libraries...
const {
dialogflow,
BasicCard,
Permission,
Suggestions,
Carousel,
SignIn
} = require('actions-on-google');
// ** code from tutorial / link **
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app)
I figured out how to do this, however it was a different method than the actions on google example. If anyone knows how to do this easier or knows what was wrong with the code in the link I posted (if anything..) please let me know / add an answer!
I decided to just write to firestore directly and put it under a "Get Signin" function (also mentioned in the tutorial for dialogflow).
Here is the function I used to get the user to sign in and also log the information into firestore:
app.intent('Get Signin', (conv, params, signin) => {
if (signin.status === 'OK') {
const payload = conv.user.profile.payload;
conv.ask(`Welcome back ${payload.name}. What can I help you with??`);
const databaseEntry = conv.user.profile.payload; // Account info, loaded to firestore
const accountRef = db.collection('Accounts').doc('account_info'); //How you want the info in firestore to appear
return db.runTransaction(t => {
t.set(accountRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
});
} else {
conv.close(`To continue, you need to make an account with the app.`);
}

Customized quick replies using Node.js Webook in Dialogflow v2

My Use case to better understand the question
I'm developing a chatbot to provide support to workers in solving problems in a hypothetic assembly line. After the bot greets the user, it advices him to identify himself with his badge number. Then, if the user accepts the bot's prompt, the bot asks for which component in a list he needs support.
Every worker can manage only a subset of set of the assembly line components.
My goal is to show to the user only the parts he is qualified to manage.
...but the real problem is here
My question is about setting Quick Replies via Node.js webhook. Here you can see
My webhook using QuickReplies(simplified)
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {QuickReplies}= require('dialogflow-fulfillment');
const https=require('https');
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function getAllowedParts(agent){
/* deleted all unuseful details*/
agent.add(new QuickReplies(['A','B','C']);
} //close getAllowedParts
let intentMap = new Map();
intentMap.set('UserIntro', getAllowedParts);
agent.handleRequest(intentMap);
});
but it doesn't work, printing in console
TypeError: QuickReplies is not a constructor
I followed what I found here and I used the WebhookClient functions at https://github.com/dialogflow/dialogflow-fulfillment-nodejs/blob/master/docs/WebhookClient.md#WebhookClient+handleRequest.
The true problem is that I can't understand what is the correct procedure to add non-default quick replies using Node.js webhook in Dialogflow v2 .
I also looked to the rich messages documentantion, but it found it very lacking on this topic.
Any help will be appreciated, thanks
You should see commented out quick reply examples set in the default index.js file in Dialogflow's console.
agent.add(new Suggestion(`Quick Reply`));
agent.add(new Suggestion(`Suggestion`));
You can also see from the Github repo there's other available methods for Quick Replies:
let suggestion = new Suggestion('reply to be overwritten');
suggestion.setReply('reply overwritten');

Categories