Discord.js: can't fetch user's connections (OAuth2) - javascript

I have a Discord app/bot with a custom linked role, and before updating metadata and adding the role, I want to fetch user's connections and look at some data from it.
More specifically, I want to assign a custom role only to users who own a specific game on Steam and have certain achievements from it. Currently stuck at fetching connections part - OAuth in general works fine.
Took this example discord oauth app:
https://github.com/discord/linked-roles-sample
And it works, except for this part: I want to fetch user's connections
Added this new function
export async function getUserConnections(tokens) {
const url = 'https://discord.com/api/v10/oauth2/#me/connections';
const response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${tokens.access_token}`,
},
});
if (response.ok) {
const data = await response.json();
return data;
} else {
throw new Error(`Error fetching user connections: [${response.status}] ${response.statusText}`);
}
}
But this fetch always returns 404, even though scope for connections is defined

Related

How to get a valid access token for a custom Azure App API? (MSAL.js)

I am trying to build a small web app which shows me my name, my schedule and my grades for school.
My school mostly uses the services from Microsoft, which gave me the idea to use their Azure API endpoints (for the schedules and grades) in my project.
I have access to create an app registration in the Azure-portal, so I did that and got it working to login with my student email. Also I tried to fetch the Microsoft Graph API and that works absolutely great.
However, when I try to fetch the Grades endpoint, it returns a 401 Unauthorized error. I'm guessing this has to do with the scopes, but I'm not sure. It turns out that my access token isn't valid for those API endpoints.
So my question is, how do I get an access token that IS valid for those API's? Or is it even possible? Keep in mind that they're separate App registrations in the Azure-portal, and that I can only edit my own one, not the one of my school.
Here is my JavaScript file, with some comments:
const config = {
auth: {
clientId: "my_client_id_is_here",
authority: "https://login.microsoftonline.com/my_tenant_id_is_here",
redirectUri: "localhost"
}
};
async function login() {
console.log("Started..")
var client = new Msal.UserAgentApplication(config);
var request = {
scopes: [ 'User.Read' ]
};
let loginResponse = await client.loginPopup(request);
console.dir(loginResponse);
let tokenResponse = await client.acquireTokenSilent(request);
console.dir(tokenResponse);
// User REQUEST - Here I fetch the Graph API for some profile information, which works fine and writes it to the HTML perfectly.
let req = await fetch("https://graph.microsoft.com/v1.0/me/", {
headers: {
"Authorization": "Bearer " + tokenResponse.accessToken
}
});
let json = await req.json();
console.log(json);
document.write("Logged in as " + json.displayName);
document.write("<br>" + json.mail);
document.write("<br>" + json.jobTitle + " " + json.officeLocation);
// School Grades REQUEST - this is the part where I'm trying to fetch my School Grades, but it's not working since it gives me a 401 error..
let gradesReq = await fetch("https://myschool.azurewebsites.net/API/Grades/GetGrades", {
"headers": {
"authorization": "Bearer " + tokenResponse.accessToken
}
});
try {
let gradesJson = await gradesReq.json();
console.log(gradesJson);
} catch (err) {
document.write("An error occured while trying to get the school grades..")
}
}```
You're correct in your thinking. The reason you're getting this error is because you're using the access token acquired for a different scope (User.Read) with your API.
Fix is rather simple.
What you have to do is protect your API with Azure AD first. You may find this link helpful in implementing this functionality: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-overview.
Once you have done that, all you need to do then is to acquire token for your API. In that case, your scopes code will be something like the following:
var request = {
scopes: [ 'api://<your-application-id>/.default' ]
};
Once you acquire the token for this scope and use it with your API, you should not get 401 exception that you're getting.

When to set the headers explicitly when making HTTP request in NodeJS application

So I was having a look at a codebase of a NodeJS application and there were some specific functions making HTTP requests to the backend. To be exact, those functions were making a GET request to the backend and one thing that I found confusing was that in some of the functions, the headers were mentioned explicitly whereas, in some other functions who were making the GET request, there was no mention of headers (i.e. headers were not being set explicitly). Below is an example:
In the code below, the function is making a GET request and there's no mention of headers (i.e. the headers are not being set explicitly):
// Method for fetching a single post from the backend on the basis of the post ID
export const singlePost = (postID) => {
return fetch(http://localhost:8080/post/${postID}, {
method: "GET",
})
.then((response) => {
return response.json();
})
.catch((error) => {
console.log(error);
});
};
In the code below, the function is making a GET request and the headers are being set explicitly:
// Helper Method for making the call to the backend and fetching all their details of all the posts
export const list = (page) => {
return fetch(http://localhost:8080/posts/?page=${page}, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
})
.then((response) => {
return response.json();
})
.catch((error) => console.log(error));
};
Now coming to the main question, could someone please explain to me when are we supposed to set the headers explicitly not only in just GET request but in other general HTTP requests as well (i.e. POST, PUT, OPTION etc).
It would be really great if some could refer a source or explain this concept here. Thanks!
HTTP request header is the information, in the form of a text record, that a user's browser sends to a Web server containing the details of what the browser wants and will accept back from the server. The request header also contains the type, version and capabilities of the browser that is making the request so that server returns compatible data.
Check this https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039

Javascript AzureAd Consume Rest Service

RestAPI: I have a Rest API running Asp Core with AzureAd Authentication.
WebApp: I have a separate WebApplication running Asp Core as backend, with Javascript frontend.
The WebApp backend authenticates through AzureAd, and then against the RestAPI to check if a user is registred.
I want the javascript client to be able to consume the Rest API directly. How should i go about this without exposing the accesstoken?
I could go about sending the request from Javascript to WebApp Backend -> Rest API. But i really want to avoid this, because of unnecessary code.
In this scenario, you can try to implement ADAL for js in your JS client. Leveraging **adal** to gain the authentication token, and when you call your Web Api, it will add the authentication header in HTTP requests.
E.G.
Suppose we want to call the Microsoft Graph API from our JS client.we develop a node.js script that uses request to call the Microsoft Graph API for groups to create a new Security Group.
The following code shows how the API is consumed from that script. Note that the token and the name are passed by parameter. Additionally, this function returns a Promise that is successfully resolved when the group is correctly created and rejected when is not.
var request = require('request');
function createGroup(token, name) {
return new Promise((resolve, reject) => {
const options = {
method: 'POST',
url: 'https://graph.microsoft.com/v1.0/groups/',
headers: {
'Authorization': 'Bearer ' + token,
'content-type': 'application/json'
},
body: JSON.stringify({
"displayName": name,
"mailEnabled": false,
"securityEnabled": true
})
};
request(options, (error, response, body) => {
const result = JSON.parse(body);
if (!error && response.statusCode == 204) {
resolve(result.value);
} else {
reject(result);
}
});
});
}
In order to call Microsoft Graph API, we needed to be authenticated and that is why in the previous section we have a token as a parameter of the function which was used to perform the request.
we should add the following code to generate the token. Note that we are using the adal npm package to do this easier, calling the acquireTokenWithClientCredentials method of the AuthenticationContext object. Additionally, we have some constants that need to be updated with the client id and secret obtained before as well as the tenant name.
var adal = require('adal-node');
const TENANT = "{tenant-name-here}.onmicrosoft.com";
const CLIENT_ID = "{Application-id-here}";
const CLIENT_SECRET = "{Application-key-here}";
function getToken() {
return new Promise((resolve, reject) => {
const authContext = new adal.AuthenticationContext(`https://login.microsoftonline.com/${TENANT}`);
authContext.acquireTokenWithClientCredentials(GRAPH_URL, CLIENT_ID, CLIENT_SECRET, (err, tokenRes) => {
if (err) { reject(err); }
resolve(tokenRes.accessToken);
});
});
Hope it helps.

How to fix/find 'Bad Request' and 'Denied' authentication errors in react

I am working on a user registration page in my group project and came across a bad request error when submitting the data. I created a button to get users so I can check the authentication and it gave me a 401. "HTTP401: DENIED - The requested resource requires user authentication. (Fetch)GET - http://localhost:49967/Users" When I login, I use the admin login that's in the database and I see a token in my developers options. How do I find this error? I am new to react and programming so if you can lend some advice or docs it would be appreciated.
So to test my api endpoint, I loaded Postman and attempted to GET/POST and everything worked. I am using a react front-end, SQL sever for the database and ASP.Net Core in Visual Studios c#.
For starters here is the const I am using to access the back end
const apiHelper = {
get(url, params){
return fetch(`${baseUrl}${url}`, {
headers: this.headers
})
.then(response => response.json())
.catch(error => {
console.log(error);
return Promise.resolve();
});
}
This is the onclick action
handleGetUsers = async() => {
const response = await apiHelper.get('Users')
if(response){
console.log(response)
}
}
Lastly my URL
http://localhost:49967/

Ionic 2 - How to use refresh token to obtain new JWT

I have an ionic 2 mobile application that uses Json Web Tokens(JWT) to authenticate to various routes on a node.js API. These JWTs have a short expire time, and need to be refreshed using a refresh token. The refresh token is just a random string that is stored both in the database and on the mobile device. Please note: I am NOT using OAuth.
How can I refactor my API calls so that they all go through one method which will send a refresh token if the initial API call gets a 401 Unauthorized response due to an expired JWT? Otherwise, I will need to write the logic for handling that response in every single API call which I would like to avoid.
Here is an example of one method I have implemented in typescript that calls the API. It is not currently handling a 401 Unauthorized response nor is it sending the refresh token yet:
public setBeerPref(beerPrefs) {
return new Promise((resolve, reject) => {
this.storage.get('email').then((email) => {
this.storage.get('token').then((token) => {
beerPrefs["email"] = email;
let headers = new Headers();
headers.append('Authorization', token);
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers });
this.http.post('apiURL', beerPrefs, options)
.subscribe(res => {
let data = res.json();
resolve(data);
resolve(res.json());
}, (err) => {
reject(err);
});
});
});
});
}

Categories