I am trying to create a folder for a user, and I have been unsuccessful with api call attempts. My code is able to receive the correct access token, so I believe the be bug would be in createFolderTestFunction below.
async function redirectToDashboard() {
console.log("redirect to dashboard");
// var response = await requestTokenSilent();
var response;
if (!response || !response.status == 200) {
response = await requestTokenPopup();
}
if (response.accessToken) {
console.log(response);
createFolderTest(response.accessToken);
// location.href = hostname;
} else {
console.log("Unable to acquire token");
}
}
function createFolderTest(accessToken) {
var options = {
method: "POST",
headers: {
Authorization: accessToken,
"Content-Type": "application/json"
},
mode: "cors",
body: JSON.stringify({
displayName: "#COOLMONDAY"
})
};
var graphEndpoint = "https://outlook.office.com/api/v2.0/me/Inbox/";
fetch(graphEndpoint, options)
.then(resp => {
console.log(resp);
})
.catch(err => {
console.log(err);
});
}
A recommendation would be to get this working in Graph Explorer first. As this eliminates any issues with language being used and access token permissions.
https://developer.microsoft.com/en-us/graph/graph-explorer/preview
The Microsoft Graph endpoint is actually https://graph.microsoft.com/ , you can use the outlook url but moving forward Graph is where we invest in documentation, sdks and tooling.
As per the documentation https://learn.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=http
You should be using, you're missing 'mailfolders'
POST /me/mailFolders
You could also use our JavaScript SDK which makes mistakes like these a little easier with intellisense and strongly typed objects.
const options = {
authProvider,
};
const client = Client.init(options);
const mailFolder = {
displayName: "displayName-value"
};
let res = await client.api('/me/mailFolders')
.post(mailFolder);
https://learn.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=javascript
Related
So i been trying to get access to the reddit api.
I registered to reddit. verified my mail. opened an app and got my credentials.
Followed this official documentation and also came across to this tutorial
All my efforts have failed and don't get any respond.
I am using nodejs. but also tried in postman and failed.
Tried 2 options using fetch and using axios:
const axios = require('axios');
const fetch = require('node-fetch')
const { URLSearchParams } = require('url')
class RedditApi {
clientId2 = "get ur own credentials by opening an app here https://www.reddit.com/prefs/apps";
clientSecret2 = "get ur own credentials by opening an app here https://www.reddit.com/prefs/apps";
authenticationUrl = `https://www.reddit.com/api/v1/access_token`;
BASE_URL = 'https://www.reddit.com/';
tokenAuth = null;
tokenExpirationTime = null;
currencyObj = null;
constructor(currencyObj) {
this.currencyObj = currencyObj;
console.log("constructor service")
}
async getAuthToken() {
const bodyParams = new URLSearchParams({
grant_type: "https://oauth.reddit.com/grants/installed_client",
device_id: "DO_NOT_TRACK_THIS_DEVICE"
});
console.log(this.clientId2, 'this.clientId');
debugger;
const headersObj = {
'Authorization': `Basic ${Buffer.from(`${this.clientId2}:`).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded',
};
let response = null;
try {
response = await axios.post(this.authenticationUrl,
bodyParams,
{
headers: headersObj
});
debugger;
} catch (error) {
debugger;
console.error(error);
console.log(error.stack);
return null;
}
}
async getAuthToken2() {
try {
// Creating Body for the POST request which are URL encoded
const params = new URLSearchParams()
params.append('grant_type', 'https://www.reddit.com/api/v1/access_token')
params.append('device_id', 'DO_NOT_TRACK_THIS_DEVICE')
// Trigger POST to get the access token
const tokenData = await fetch('https://oauth.reddit.com/grants/installed_client', {
method: 'POST',
body: params,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${Buffer.from(`${this.clientId2}:`).toString('base64')}` // Put password as empty
}
}).then(res => {
debugger;
return res.text()
})
debugger;
if (!tokenData.error) {
debugger;
res.send(trendingResult)
}
res.status(tokenData.error).send(tokenData.message)
} catch (error) {
debugger;
console.log(error)
}
}
}
module.exports = RedditApi;
when using axios i get this respond: "Request failed with status code 401"
When using fetch i get this respond: "'403 Forbidden\nRequest forbidden by administrative rules.\n\n'"
Anybody knows what is the problem and how can i fix it?
Many thanks!
This Netlify function should run as an endpoint on example.com/.netlify/functions/github and is supposed to proxy a fetch request from my website, reach out to the GitHub API and send data back to the website.
As far as I have understood, I can use to GET data from the GitHub API without authentication. Hitting their API directly in the browser works: https://api.github.com/orgs/github/repos?per_page=2 (also works from Postman).
The data is an array of objects where each object is a repository.
There has been multiple issues the past couple of years where Netlify functions (running on AWS lambdas) have had hickups that resulted in error messages similar to mine, so I'm confused whether this is an error in my code or something weird on their side.
First, the proxy function which – according to the Netlify admin console – runs without error. In a support article Netlify requires the result returned as JSON.stringify(), so I follow that convention here:
const fetch = require('node-fetch')
const url = 'https://api.github.com/orgs/github/repos?per_page=2'
const optionsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
}
const fetchHeaders = {
'Content-Type': 'application/json',
'Host': 'api.github.com',
'Accept': 'application/vnd.github.v3+json',
'Accept-Encoding': 'gzip, deflate, br'
}
exports.handler = async (event, context) => {
if (event.httpMethod === 'OPTIONS') {
return {
'statusCode': '200',
'headers': optionsHeaders,
}
} else {
try {
const response = await fetch(url, {
method: 'GET',
headers: fetchHeaders
})
const data = await response.json()
console.log(JSON.stringify({ data }))
return {
statusCode: 200,
body: JSON.stringify({ data })
}
} catch (err) {
console.log(err)
}
}
}
Client fetch that hits https://example.com/.netlify/functions/github. URL is correct, the function is executed (verified that in the Netlify admin panel):
const repos = document.querySelectorAll('.repo')
if (repos && repos.length >= 1) {
const getRepos = async (url) => {
try {
const response = await fetch(url, {
method: "GET",
mode: "no-cors"
})
const res = await response.text()
// assuming res is now _text_ as per `JSON.stringify` but neither
// that nor `.json()` work
console.log(res[0].name)
return res[0].name
} catch(err) {
console.log(err)
}
}
const repoName = getRepo('https://example.com/.netlify/functions/github')
repos.forEach((el) => {
el.innerText = repoName
})
}
Not 100% sure where this error message originates from, it is probably not the console.log(err) although it displays in the browser console, because the error code is 502 and the error also shows up directly in the response body in Postman.
error decoding lambda response: error decoding lambda response: json: cannot unmarshal
string into Go value of type struct { StatusCode int "json:\"statusCode\""; Headers
map[string]interface {} "json:\"headers\""; MultiValueHeaders map[string][]interface {}
"json:\"multiValueHeaders\""; Body string "json:\"body\""; IsBase64Encoded bool
"json:\"isBase64Encoded,omitempty\""; Metadata *functions.Metadata
"json:\"metadata,omitempty\"" }
Haven't found any clear information on this issue, could any of you enlighten me?
The only response that don't comply with the schema is the preflight request. From the error message, I assume you need to change:
'statusCode': '200',
to
'statusCode': 200, // StatusCode int
Even better, because there's no content, you may want to use 204 instead.
If that's still not enough, I may still want to include the body there as well, as it doesn't seem optional:
return {
'statusCode': 204,
'headers': optionsHeaders,
'body': ''
}
*My goal here is to get the location of bikes from a bike-sharing company's API.
I did Steps 1 and 2 using Postman. but ill try to integrate it into my code once I get the hang of it.
The first step is to verify your email and generate an Auth token. This requires only a verifiable email address. Make a POST request to https://web.spin.pm/api/v1/magic_links with the body:
{"email": "sampleemail#gmail.com"}
From there, you will need to find the token within your email. This token needs to be sent with a POST request to
https://web.spin.pm/api/v1/auth_tokens with the body:
{
"grant_type": "magic_link",
"magic_link": {
"email": "<email>",
"token": "<token>"
}
}
This request returns a JSON that looks like this: {"jwt":"eyJ0eXAiOiJ.....cXVLw","refreshToken":"2cb07....bab5030","existingAccount":false}
To get the position of vehicles so a GET-Request to https://web.spin.pm/api/v3/vehicles?lng=-77.0146489&lat=38.8969363&distance=&mode= User Header Authorization: Bearer to Authenticate and use the jwt-Token we got from the Auth request.
You will get something like this as return JSON {"vehicles":[{"lat":37.69247,"lng":-122.46595,"last4":"3595","vehicle_type":"bicycle","batt_percentage":null,"rebalance":null}, … ]}
Step 3 is done using (async/awit function) using fetch where I am having the problem with. I copy-pasted the jwt in my .env file and set up the proper headers.
I get a 401 response when making the call. when I tested step 3 using postman everything seems to work fine.
I have attached a screenshot of the error in this post. Hopefully its more clear, Thanks in advance.
const fetch = require("node-fetch");
require('dotenv').config();
async function getBikes()
{
const lat = '38.897574612438575';
const lng = '-77.01855164084469';
const api_url = `https://web.spin.pm/api/v3/vehicles?lng=${lng}&lat=${lat}&distance=&mode=`;
const jwt_key = process.env.BERER_KEY;
try{
const config = { method: 'GET',
headers: {json: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer'+ jwt_key
} },
rejectUnauthorized: false
};
const response = await fetch(api_url,config );
const data = await response.json(); //response.json() //headers //.jwt; //response.json()
if (response.ok)
{
console.log("STATUS CODE IS: "+response.status);
console.log('My JWT:', response);
return data;
}
else{
console.log("something went wrong ");
console.log("STATUS CODE IS: "+ response.status);
console.log( response);
}
} catch (error) {
console.log(error);
}
}
const y = getBikes();
console.log(y)
BEARER_KEY=eyJhbGciOiJIUzI1NiJ9.eyJ1c2V
I seem to be having an issue with getting the expected response from a fetch call within a firebase cloud function. I'm sure it's due to my lack of knowledge on how the responses, promises, etc. work.
I'm trying to use atlassian crowd's rest api for SSO. If I use postman, I can get the desired results from the request. So I know that part of it is working.
What led me to using a cloud function is that making the same request using fetch was resulting in CORS issues from localhost. I figured if I can take the browser out of the equation, then the CORS issues would disappear. Which they have, but I'm not getting the desired response.
My cloud function looks like this:
const functions = require('firebase-functions');
const fetch = require('node-fetch');
const btoa = require('btoa');
const cors = require('cors')({origin:true});
const app_name = "app_name";
const app_pass = "app_password";
exports.crowdAuthentication = functions.https.onRequest((request, response)=>
{
cors(request, response, () =>{
let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
let _headers = {
'Content-Type':'application/json',
'Authorization':`Basic ${btoa(`${app_name}:${app_pass}`)}`
}
let _body = {
username: request.body.username,
password: request.body.password
}
const result = fetch(_uri, {
method: 'POST',
headers: _headers,
body: JSON.stringify(_body),
credentials: 'include'
})
response.send(result);
})
})
I'm then making the call in my application using fetch to the firebase endpoint and passing the username/password:
fetch('https://my.firebase.endpoint/functionName',{
method: 'POST',
body: JSON.stringify({username:"myusername",password:"mypassword"}),
headers: {
'Content-Type':'application/json'
}
})
// get the json from the readable stream
.then((res)=>{return res.json();})
// log the response - {size:0, timeout:0}
.then((res)=>
{
console.log('response: ',res)
})
.catch(err=>
{
console.log('error: ',err)
})
Thanks for looking.
Edit of May 2020
Note that request-promise is deprecated and I recommend to use axios.
Update following our discussion in the comments below
It appears that it doesn't work with the node-fetch library and that you should use another library like request-promise.
Therefore you should adapt your code as follows:
//......
var rp = require('request-promise');
exports.crowdAuthentication = functions.https.onRequest((request, response) => {
cors(request, response, () => {
let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
let _headers = {
'Content-Type': 'application/json',
'Authorization': `Basic ${btoa(`${app_name}:${app_pass}`)}`
}
let _body = {
username: request.body.username,
password: request.body.password
}
var options = {
method: 'POST',
uri: _uri,
body: _body,
headers: _headers,
json: true
};
rp(options)
.then(parsedBody => {
response.send(parsedBody);
})
.catch(err => {
response.status(500).send(err)
//.... Please refer to the following official video: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
});
});
});
Initial answer with node-fetch
The fetch() method is asynchronous and returns a Promise. You therefore need to wait this Promise resolves before sending back the response, as follows:
exports.crowdAuthentication = functions.https.onRequest((request, response)=>
{
cors(request, response, () =>{
let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
let _headers = {
'Content-Type':'application/json',
'Authorization':`Basic ${btoa(`${app_name}:${app_pass}`)}`
}
let _body = {
username: request.body.username,
password: request.body.password
}
fetch(_uri, {
method: 'POST',
headers: _headers,
body: JSON.stringify(_body),
credentials: 'include'
})
.then(res => {
res.json()
})
.then(json => {
response.send(json);
}
.catch(error => {
//.... Please refer to the following official video: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
});
})
})
In addition, note that you need to be on the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse on the question mark situated after the "Cloud Functions" title)
I want to fetch my tasks within Javascript and possibly add new ones, but let's focus on fetching a task.
I made an app and use the msal.js file to get a token. I get prompted to allow the app to read/write from my account, the popup closes and I've obtained a token!
So far so good, but when I try to fetch my tasks the API responds with "unauthorized". When I check the headers I can see I sent along "bearer [token]" however.
I'm completely clueless on how to get my tasks by now since I did get a proper token and I've followed the guided setup to make sure I send along the token.
In my app (which I created on https://apps.dev.microsoft.com) I've set all Task related permissions and User.read for good measure. As for the platform I've set "Web".
Is there something I'm missing or mis-configuring?
My init method:
const self = this
this.userAgentApplication = new Msal.UserAgentApplication(this.clientID, null, function (errorDes, token, error, tokenType) {
// this callback is called after loginRedirect OR acquireTokenRedirect (not used for loginPopup/aquireTokenPopup)
})
this.userAgentApplication.loginPopup(['Tasks.readwrite']).then(function (token) {
let user = self.userAgentApplication.getUser()
if (user) {
self.token = token
localStorage.setItem('token', token)
self.getTasks()
}
}, function (error) {
console.log(error)
})
My getTasks method:
const bearer = 'Bearer ' + this.token
let headers = new Headers()
headers.append('Authorization', bearer)
let options = {
method: 'GET',
headers: headers
}
// Note that fetch API is not available in all browsers
fetch('https://outlook.office.com/api/v2.0/me/tasks', options).then(function (response) {
let contentType = response.headers.get('content-type')
if (response.status === 200 && contentType && contentType.indexOf('application/json') !== -1) {
response.json().then(function (data) {
console.log(data)
})
.catch(function (error) {
console.log(error)
})
} else {
response.json().then(function (data) {
console.log(data)
})
.catch(function (error) {
console.log(error)
})
}
})
.catch(function (error) {
console.log(error)
})
Your token is scoped for Graph, not Outlook. Tasks.readwrite will default to the Microsoft Graph and won't work against the Outlook endpoint.
Change this bit:
this.userAgentApplication.loginPopup(['Tasks.readwrite'])
To:
this.userAgentApplication.loginPopup(['https://outlook.office.com/Tasks.readwrite'])
You are trying to use Microsoft Graph, so the request should look like
GET https://graph.microsoft.com/beta/users/{id|userPrincipalName}/outlook/tasks
It's documented here:https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/outlookuser_list_tasks
I believe you got a Microsoft Graph token but you're trying to use it on the Outlook REST endpoint, which would not work.