Wikidata REST API Forbidden using Access Token? - rest

I have this Node.js request:
/* eslint-disable #typescript-eslint/no-unsafe-member-access */
/* eslint-disable #typescript-eslint/no-unsafe-assignment */
import * as dotenv from 'dotenv'
dotenv.config()
const id = process.argv[2]
download(id)
async function download(id: string) {
// const query = new URLSearchParams({ query: sparql }).toString()
// const url = `https://www.wikidata.org/w/rest.php/wikibase/v0/entities/items/${id}/statements`
// test
const url = `https://www.wikidata.org/w/rest.php/wikibase/v0/entities/items/Q42/statements`
const res = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.WIKIDATA_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
})
console.log(res)
const json = await res.json()
console.log(json)
}
The WIKIDATA_ACCESS_TOKEN is straight from my newly created OAuth client following the REST API docs.
I am getting an error at res.json():
{ error: 'rest-read-denied', httpCode: 403, httpReason: 'Forbidden' }
Why is this not working? I haven't been spamming the system, I just made a couple requests. I checked process.env.WIKIDATA_ACCESS_TOKEN and it does have the correct access token... Is there a step or configuration that I am missing?
Here is the client info.

Related

Redeliver existing form submission to new webhook

I have set up a webhook between salesforce and Typeform and it's working fine. But Typeform has already filled form submissions. Now I want to deliver these responses to a new webhook is there a way to resync existing form submissions?
I dont think this is possible out of the box. You will need to fetch your responses via Typeform Responses API and feed them to your script or webhook.
It looks like the webhook payload is quite similar to the response returned by the API. You can write a script like this to feed all your existing responses from your typeform to a new webhook:
import fetch from 'node-fetch'
import crypto from 'crypto'
import { createClient } from '#typeform/api-client'
const token = process.env.TF_TOKEN // https://developer.typeform.com/get-started/personal-access-token/
const webhookSecret = process.env.SECRET
const uid = process.env.FORM_ID
const typeformAPI = createClient({ token })
const sleep = async (ms) => new Promise(res => setTimeout(res, ms))
// based on https://glitch.com/edit/#!/tf-webhook-receiver
const calculateSignature = (payload) => {
const hash = crypto
.createHmac('sha256', webhookSecret)
.update(payload)
.digest('base64')
return `sha256=${hash}`
}
const feedResponses = (before) => {
typeformAPI.responses.list({ uid, before }).then(async ({ items }) => {
if (items.length > 0) {
// process each response
for (let i=0; i<items.length; i+=1) {
const item = items[i]
const body = JSON.stringify({
"event_id": Date.now(),
"event_type": "form_response",
"form_response": item
})
const response = await fetch('/your-endpoint', {
method: 'POST',
headers: {
'Typeform-Signature': calculateSignature(body)
},
body,
})
const webhookResponse = await response.text()
console.log(webhookResponse)
await sleep(250) // rate-limit the requests
}
// continue with next page of responses
const { token } = items.at(-1)
feedResponses(token)
}
})
}
feedResponses()

Cookie does not appear to be sent via fetch or hapi server is unable to receive cookie

So I have a simple backend server created with Hapi API and the frontend I'm using fetch. These are on different ports so I have CORs enabled and all the sweet stuff. I'm currently trying to set a refresh token in the browser using a http only cookie. As far as I can verify, the http only cookie is being set in the browser when login function is completed. I'm currently trying to send the http only cookie back to the server so I can set up the refresh token route and I can't seem to send or even verify that http token is sent back to the server.
Here's the server setting.
"use strict";
require("dotenv").config();
const Hapi = require("#hapi/hapi");
const Jwt = require("#hapi/jwt");
const routes = require("./routes/routes");
exports.init = async () => {
const server = Hapi.server({
port: 3000,
host: "localhost",
routes: {
cors: {
origin: ["*"],
credentials: true,
},
},
});
require("./models");
await server.register(Jwt);
server.auth.strategy("jwt", "jwt", {
keys: { key: process.env.SECRET_KEY, algorithms: ["HS256"] },
verify: { aud: false, iss: false, sub: false, exp: true },
validate: false,
});
server.state("refresh", {
ttl: 1000 * 60 * 60 * 24,
isSecure: true,
isHttpOnly: true,
encoding: "base64json",
clearInvalid: true,
strictHeader: true,
isSameSite: "None",
});
server.route(routes);
return server;
};
process.on("unhandledRejection", (err) => {
console.log(err);
process.exit(1);
});
Here's the login request and returns the http only cookie. This part works, the http cookie is returned and set.
const validateUserAndReturnToken = async (req, h) => {
const user = await User.findOne({
$or: [{ email: req.payload.username }, { username: req.payload.username }],
});
if (user) {
const match = await bcrypt.compare(req.payload.password, user.passwordHash);
if (match) {
const token = await createToken(match);
const refreshToken = await createRefreshToken(match);
h.state("refresh", refreshToken);
return { id_token: token, user: formatUser(user) };
} else {
throw boom.notAcceptable("Username and password did not match.");
}
} else {
throw boom.notAcceptable("Username or email was not found.");
}
};
Here's the fetch request I'm using to test sending a http cookie only back. I have credential: include so I don't know what is problem?
import type { DateInfo } from "#/stores/application";
const api = "http://localhost:3000/report";
let token = localStorage.getItem("user-token");
const headers = new Headers();
headers.append("Authorization", `Bearer ${token}`);
headers.append("Content-Type", "application/json");
export const getJobReport = async (dateFilter: DateInfo) => {
let response = await fetch(
`${api}/${dateFilter.startDate}/${dateFilter.endDate}`,
{
method: "GET",
headers,
credentials: "include",
}
);
return await response.json();
};
I have checked the application tab as well as the network request so I know set cookie is being sent and set on the browser. The problem is I can't seem to get the cookie back from the browser when fetch request is sent back to the server.
Here's the code I'm using to just check the existence of the cookie. According to Hapi Doc , req.state[cookie-name] which in this case is 'refresh' should have the cookie value. Refresh is returning undefined so I went up one level and check for req.state and gets an empty object {}.
route
{
method: "GET",
path: "/report/{startDate}/{endDate}",
options: {
auth: "jwt",
state: {
parse: true,
failAction: "error",
},
validate: {
params: Joi.object({
startDate: Joi.string(),
endDate: Joi.string(),
}),
},
},
handler: handlers.report.getJobApplicationReport,
},
handler
const getJobApplicationReport = async (req, h) => {
console.log("TEST", req.state);
const start = new Date(req.params.startDate);
const end = new Date(req.params.endDate);
try {
const applications = await Application.find({
dateApplied: { $gte: start, $lt: end },
});
// 'Applied', 'In Process', 'Rejected', 'Received Offer'
const total = applications.length;
let rejectedCount = 0;
let inProcessCount = 0;
applications.forEach((app) => {
if (app.status === "Rejected") {
rejectedCount++;
}
if (app.status === "In Process") {
inProcessCount++;
}
});
return {
total,
rejectedCount,
inProcessCount,
};
} catch (error) {
console.log(error);
throw boom.badRequest(error);
}
};
I've looked through all the Hapi documentation, fetch documentation and stackoverflow question/answers but can't seem to find a solution. I can't verify whether it's the fetch request that's not sending the http only cookie or the server setting that's not parsing it. Any help to determine the issue or solution would be greatly appreciated.
I've looked through all the Hapi documentation, fetch documentation and stackoverflow question/answers but can't seem to find a solution. I can't verify whether it's the fetch request that's not sending the http only cookie or the server setting that's not parsing it. Any help to determine the issue or solution would be greatly appreciated.

Surprisingly I'm getting same code for access_token and id_token

I have angular app version 6 and I'm trying to integrate Azure AD authentication and the micro services are in AWS.
Surprisingly I'm getting same code for access_token and id_token.
are they supposed to be different? my architect thinks so and asked me to tweak library to send responseType as 'id_token+token'.
What am I doing wrong and is there any way I can get access_token for sending as headers for api calls?
I have also attached the screenshot of the console errors of api c
microsoftadal-api fails
alls.
Below is my piece of code where I was trying to read access token for authenticating api calls.
enter code here
export class AppComponent {
loading: boolean;
constructor(private adalSvc: MsAdalAngular6Service, private router: Router,
private http: HttpClient) {
this.adalSvc.acquireToken('https://api.test.test.com/Dev')
.subscribe((resToken: string) => {
console.log(this.adalSvc.userInfo);
console.log('get resToken -->', resToken);
console.log('get oid -->', this.adalSvc.userInfo.profile.oid);
console.log('get accessToken -->', this.adalSvc.accessToken);
localStorage.setItem('accessToken', this.adalSvc.accessToken);
console.log('get token -->', this.adalSvc[enter image description here][1]
.getToken('https://api.test.test.com/test?userId=111111'));
this.configureRoutes();
this.loading = true;
this.http.get('https://api.test.test.com/test?userId=11111', {
headers: {
'Authorization': 'Bearer ' + this.adalSvc.accessToken,
'userid': this.adalSvc.userInfo.profile.oid,
'username': 'username',
'userrole': 'somerole'
}
}).subscribe(console.log);
this.postCall();
},
error => {
console.log(error);
});
}
postCall() {
const data = {
'dealerId': '111111'
};
const headers = new Headers();
headers.append('Authorization', 'Bearer ' + this.adalSvc.accessToken);
headers.append('userid', this.adalSvc.userInfo.profile.oid);
headers.append('username', 'username');
headers.append('userrole', 'somerole');
return this.http.post(
'https://api.test.test.com/test', data, {
headers: {
'Authorization': 'Bearer ' + this.adalSvc.accessToken,
'userid': this.adalSvc.userInfo.profile.oid,
'username': 'username',
'userrole': 'somerole'
}
}).subscribe((response: Response) => {
console.log(response.json());
});
}
configureRoutes() {
this.router.navigate(['/dealer/home']);
}
}
Make sure that you have specified the right resource.
It's the id_token and not the access_token that you need to send to your backend APIs. Then you can get the access_token from the id_token.
It looks like you might be making the same mistake that the user here made.

Passport-jwt issue : JWT token is working with postman but not working with UI api call

I have integrated passport-jwt for authentication purpose. It's working like charm but whenever Frontend guy use it from frontend angular 2 its giving Unauthorised 401 . I've tried alot but not getting any clue, it must be a silly mistake though.
my passport strategy file is as
let JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
//let fromHeader = require('passport-jwt').fromHeader
// load up the user model
const User = require('../components/user/model');
const database = require('./database'); // get db config file
const config = require('./config'); // get db config file
module.exports = function(passport) {
//var passportStrategy = function(passport){
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
//opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("JWT");
console.log("opts.jwtFromRequest==",opts.jwtFromRequest);
opts.secretOrKey = config.secret;//config.secret;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
//console.log("opt==",JSON.stringify(opt));
//console.log("jwt_payload===",jwt_payload);
User.findOne({_id: jwt_payload._doc._id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
};
my route is as
app.get("/api/user/getAll",
passport.authenticate('jwt',{session:false}),
userController.fetchUsers
);
And frontend header append is as follows :
logoutUser(token) {
//const userData = JSON.stringify(userInfo);
var headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', token); //e.g.token = JWT dasddddasdsda
//headers.append('Authentication', token);
console.log(headers)
return this.http.post('http://localhost:9000/api/user/logout', { headers: headers })
.map((response: Response) =〉 {
return response.json()
})
.catch(this.errorHandler);
}
It would really great if anyone can assist me further to identify the mistake.
Second argument for the post method is payload.
so this code below
this.http.post('http://localhost:9000/api/user/logout', { headers: headers })
has to be
this.http.post('http://localhost:9000/api/user/logout', {}, { headers: headers })

How to translate superagent to axios?

I have some upload working for superagent. It involves posting to an api for cloudinary. My question is how do I do the same thing with axios. I'm not sure what superagent.attach and superagent.field relate to in axios.
Basically when I make the post request I need to attach all these fields to the request or else I get bad request and I want to do this in axios not superagent as I am switching over to axios.
Here are all the params:
const image = files[0];
const cloudName = 'tbaustin';
const url = `https://api.cloudinary.com/v1_1/${cloudName}/image/upload`;
const timestamp = Date.now()/1000;
const uploadPreset = 'cnh7rzwp';
const paramsStr = `timestamp=${timestamp}&upload_preset=${uploadPreset}ORor-6scjYwQGpNBvMW2HGMkc8k`;
const signature = sha1(paramsStr);
const params = {
'api_key': '177287448318217',
'timestamp': timestamp,
'upload_preset': uploadPreset,
'signature': signature
}
Here is the superagent post request:
let uploadRequest = superagent.post(url)
uploadRequest.attach('file', image);
Object.keys(params).forEach((key) => {
uploadRequest.field(key, params[key]);
});
uploadRequest.end((err, res) => {
if(err) {
alert(err);
return
}
You would need to use FromData as follows:
var url = `https://api.cloudinary.com/v1_1/${cloudName}/upload`;
var fd = new FormData();
fd.append("upload_preset", unsignedUploadPreset);
fd.append("tags", "browser_upload"); // Optional - add tag for image admin in Cloudinary
fd.append("signature", signature);
fd.append("file", file);
const config = {
headers: { "X-Requested-With": "XMLHttpRequest" },
onUploadProgress: function(progressEvent) {
// Do something with the native progress event
}
};
axios.post(url, fd, config)
.then(function (res) {
// File uploaded successfully
console.log(res.data);
})
.catch(function (err) {
console.error('err', err);
});
See full example here