JitBit Helpdesk API - authentication

Wondering if anyone else is using the JitBit Helpdesk software and their API
https://www.jitbit.com/helpdesk/helpdesk-api/
We are unable to authenticate to the interface as it returns a 401 every time. I'm not sure if we are setting the headers incorrectly or if we need to enable something in the ticketing software to allow us access.
https://www.programmableweb.com/api/jitbit-helpdesk/sample-source-code
We've tried connecting through node and python and receive the same results. Here is an example of what i'm using through node
const options = {
url: 'https://helpdesk/api/Authorization',
rejectUnauthorized: false,
headers: {
Authorization: "Basic " + Buffer.from('Domain\\username' + ":" + 'password').toString('base64')
}
}
function callback(error, response, body) {
console.log(response)
if (!error && response.statusCode == 200) {
const info = JSON.parse(body);
console.log('success',info)
}
}
request(options,callback)
I had to set the rejectUnauthorized to false, it was saying it couldn't return the certificate (UNABLE_TO_GET_ISSUER_CERT_LOCALLY). Not sure if that could be the issue.
Any help would be greatly appreciated.

Got it resolved. We had anonymous access disabled. It was recommend by support to have this enabled otherwise you'll run into issues such as authenticating to the API.

Related

Get a JSON file from an AppScript backend, using an AppScript front end, without getting a CORS error?

I'm trying to build a an API-driven front end in Google AppsScript that calls a REST API hosted on AppScript to make some database queries.
I am currently simply trying to retrieve a JSON file with a GET request.
Everything I try, I get "CORS Missing Allow Origin".
My understand of CORS is that I might experience this with POST request (but maybe there's some people who have phrased their requests to get work this?)
I have a sense that the situation has changed over time, and what has worked in previous SO threads, doesn't seem to work for me now.
Sigh. I feel like Google's Documentation Team would benefit from a dedicated article to explaining how this is supposed to work.
If anyone can shed light on how I can get this to work, I've be most grateful:
client side code:
useEffect(() => {
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all', {
redirect: "follow",
headers: {
"Content-Type": "text/plain",
},
})
.then(result => result.json())
.then(rowData => setRowData(rowData))
}, []);
Server side code:
export function doGet(e) {
if (e.pathInfo.startsWith('get/all')) {
return getAllRecords(e);
}
else if (e.pathInfo.startsWith('get')) {
return getRecord(e);
}
else {
return getAllRecords(e);
//return HtmlService.createHtmlOutput('Error: invalid path- ' + e.pathInfo + '\n\n' + e.parameter + e);
}
}
function getAllRecords(e) {
// Connect to the MySQL database using the JDBC connector
const conn = Jdbc.getConnection(url, username, password);
// Construct the SELECT statement
const sql = `SELECT * FROM cars LIMIT 100`;
// Execute the INSERT statement
const stmt = conn.prepareStatement(sql);
const results = stmt.executeQuery();
// Return the inserted record with the generated id
const records = [];
while (results.next()) {
const record = {
id: results.getInt('id'),
name: results.getString('name'),
make: results.getString('make'),
price: results.getInt('price')
};
records.push(record);
}
return ContentService.createTextOutput(JSON.stringify(records)).setMimeType(ContentService.MimeType.TEXT);
// return ContentService.createTextOutput(JSON.stringify(records)).setMimeType(ContentService.MimeType.JAVASCRIPT);
}
I've tried various combination of MIME Type, and request headers and I'll try any combinations people suggest.
In order to use pathInfo, in this case, it is required to use the access token. I thought that this might be the reason for your current issue. But, when the access token is used, I'm worried that is might not be useful for your actual situation. So, in this answer, I would like to propose the following 2 patterns.
Pattern 1:
In this pattern, your script is modified using the access token. In this case, please modify your Javascript as follows.
From:
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all', {
redirect: "follow",
headers: {
"Content-Type": "text/plain",
},
})
.then(result => result.json())
.then(rowData => setRowData(rowData))
To:
const accessToken = "###"; // Please set your access token.
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all?access_token=' + accessToken)
.then(result => result.json())
.then(rowData => setRowData(rowData))
When you use the access token, please include the scopes of Drive API. Please be careful about this.
Pattern 2:
In this pattern, I would like to propose the modification without using the access token. When the access token cannot be used, unfortunately, pathInfo cannot be used. So, in this pattern, the query parameter is used instead of pathInfo.
Please modify your Javascript as follows.
From:
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec/get/all', {
redirect: "follow",
headers: {
"Content-Type": "text/plain",
},
})
.then(result => result.json())
.then(rowData => setRowData(rowData))
To:
fetch('https://script.google.com/macros/s/AKfycbz3_hgjZe0E35ZI2mw7aNs3ASkYCct77qIzL_WTOQMu_ZZeax9WpHpPIwm-MFPhZAW77g/exec?value=get%2Fall') // or ?value=get
.then(result => result.json())
.then(rowData => setRowData(rowData))
And also, please modify doGet of your Google Apps Script as follows.
Modified script:
function doGet(e) {
if (e.parameter.value == "get/all") {
return getAllRecords(e);
} else if (e.parameter.value = "get") {
return getRecord(e);
} else {
return getAllRecords(e);
}
}
Note:
In this modification, it supposes that your getAllRecords(e) works fine. Please be careful about this.
And, in this modification, it supposes that your Web Apps is deployed as Execute as: Me and Who has access to the app: Anyone. Please be careful about this.
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".
Thit is a sample modification. So, please modify this for your actual situation.
Reference:
Taking advantage of Web Apps with Google Apps Script (Author: me)

CORS header ‘Access-Control-Allow-Origin’ missing on response in addon but not on request

I am creating a Firefox extension which posts some data to a database.
I made all parts in a modular fashion and am now combining everything piece by piece.
As such I know that my code to POST data to the database works.
Now here is the part that stumps me :
When I then add this code to my firefox extension
I get the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3003/timed_shot_create. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 400.
Now ofcourse CORS was nothing new and to be expected when dealing with Cross Origin Resource Sharing, it is even in the name.
But the reason why I am here is because this pertains only to the response of the POST request. The request itself is fine and allowed with the following piece of config in the server:
app.use(
cors({
//todo change to proper origin when live
origin: "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d",
method: ["GET", "POST"],
})
);
Which was later changed to:
app.use(
cors({
origin: "*",
method: ["GET", "POST"],
})
);
And then simplified even more to:
app.use(cors())
This is in Nodejs btw using cors middleware.
But none of this seems to work when it is used inside a firefox extension, as a local client page works as intended but as soon as I add this to a firefox extension I get a CORS error specifically pertaining to the reponse message.
The client side post (in the background script of the extension) is:
async function postTimedShot(post_options) {
const response = await fetch(post_endpoint, post_options);
//console.log(response);
const json_response = await response.json();
console.log(json_response);
}
let post_options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(response_data),
};
postTimedShot(post_options);
And the api looks like this:
app.post("/timed_shot_create", (req, res) => {
console.log("Received POST request");
const data = req.body;
console.log(data);
const timeStamp = data.time_stamp;
//TODO add screenshot and Description text maybe??
//const lastName = data.last_name
const queryString =
"INSERT INTO " + timed_shots_database + " (time_stamp) VALUES (?)";
getConnection().query(queryString, [timeStamp], (err, results, fields) => {
if (err) {
console.log("Failed to insert new user: " + err);
res.sendStatus(500);
return;
}
//Todo change this message when adding more data in body
//res.header("Access-Control-Allow-Origin", "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d");
res.json({
status: "Success!!!",
time_stamp: timeStamp,
});
console.log("Inserted a new user with id: ", results.insertId);
});
});
Furthermore, this extension is only for personal use and will work with a local server under my complete control so complications due to security or cloud usage that people want to mention are appreciated but not necessary (I think, I am a bit of novice).
I will be happy to clarify anything that is unclear, or change this post if necessary, but I think it is a unique question as far as I could see on SO. Additionally if I need to provide more of the codebase I will.
I will also update this post if I find out more about this problem.
Thank you for reading :3.
After reading about this post https://stackoverflow.com/a/53025865/5055963
on SO I found out that it had to do with the permissions in the manifest of the extension.
Adding this line: "://.localhost/*".
Solved the issue for me.

Why does the browser ask me to log in with ASP.NET Core 3.1

I've created a website in ASP.NET Core 3.1, MVC, with API. There are 2 parts to the website. An classic static website (with a home, about, contact page etc) and a SPA app. You need to login to use the SPA application.
I believe my approach to auth is quite 'standard'. (There are no different permissions or roles).
The user logs in, and an HTTP Only cookie is created. They are redirected to the Web API part of the website
Any API calls to the C# Web Api, and the front end reviews the return status code (such as code 200 or 500 etc).
If the return is 401, it will assume the JWT has expired or has never been created. The front end then makes another call to the Web Api to retrieve a new Json Web Token. If the JWT is returned, the program attempts the original request again, with the valid JWT. Otherwise, it deals with the situation by alerting the user about the issue
The ajax code looks like
function toDatabase(type, url, data, successDelegate, failDelegate, errorDelegate, tryAgainIfUnathorized) {
$.ajax({
type: type.toUpperCase(),
url: url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + bearerToken.get()
},
data: data,
dataType: "json",
success: function (response) {
successDelegate(response);
},
error: function (e) {
if (e.status === 401 && tryAgainIfUnathorized) {
const callback = function () {
toDatabase(type, url, data, successDelegate, failDelegate, errorDelegate, false, false);
};
bearerToken.refresh(callback);//try to get the updated token, then retry the original request
}
else {
if (e.status !== 200)
errorDelegate(e.statusText);
console.log("Error in ajaxCall.js. Expand for call stack:");
console.log(e);
}
}
});
This works fine on my local computer.
The problem is, seemingly randomly and not that often, on my production site, Google Chrome occasionally presents a log in dialog. My code does not create this dialog. I don't even know the javascript to create it :)
I don't understand. If I click cancel, then I can continue as I'd like (meaning I am authenticated).
I read up, and it seems that this happens because the browser detects the 401 and tries to be helpful!
I've tried to get round this issue by returning a 499 instead of a 401 but that caused even more headaches with this code
jwtBearerOptions.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
context.Response.OnStarting(() =>
{
context.Response.StatusCode = 499;
return Task.CompletedTask;
});
return Task.CompletedTask;
}
};
How do I prevent this dialog from showing (or is my approach to using JWT incorrect)

Cloud Recoding RESTful API Error of Agora.io

I would like to implement your Cloud Recoding of Live Broadcasting via RESTful API. I implemented it with NodeJs. Could you please help me why I get an error and how I can fix it?
On the manual,
"Status Code 400: The input is in the wrong format."
But I do not know what is wrong.
error: null
body: { resourceId: '', code: 400 }
var plainCredentials = new Buffer.from(agoraCustomerId+":"+agoraCustomerCertificate);
var base64Credentials = plainCredentials.toString("base64");
var options = {
url: "https://api.agora.io/v1/apps/AGORA_APP_ID/cloud_recording/acquire",
method: "POST",
headers: {
"Authorization": "Basic " + base64Credentials,
"Content-type": "application/json;charset=utf-8"
},
body:{
"cname": "190724060650293",
"uid": "060716332",
"clientRequest": {}
}
};
request.post(options, function (error, response, body) {
console.log("error: " + error);
console.log("body: ", body);
});
Agora's Cloud Recording is an add-on feature so it's not enabled by default, it needs to be enabled on your account for a specific AppID. The error you may be receiving is because the feature is not enabled on your account.
UPDATE:
Enabling Agora.io's Cloud Recording on your project is now available through the Agora.io Dashboard.
To enable Cloud Recording on your project, you’ll need to click into the Products & Usage section of the Agora.io Dashboard and select the Project name from the drop-down in the upper left-hand corner, click the Duration link below Cloud Recording.
After you click Enable Cloud Recording, you will be prompted to confirm the concurrent channels settings which defaults to 50, but you can contact sales#agora.io if you need more.
Theres a getting started tutorial that leverages a POSTMAN collection for quick testing.
QuickStart Tutorial: https://medium.com/#hermes_11327/agora-cloud-recording-quickstart-guide-with-postman-demo-c4a6b824e708
Postman Collection: https://documenter.getpostman.com/view/6319646/SVSLr9AM?version=latest
In my case it was mistake in Region settings . I used AP_NORTHEAST_1 but 10 need be used
1 - Make sure you have enable agora recording
2- Check the link and send all parameters.
https://docs-preprod.agora.io/en/cloud-recording/cloud_recording_webpage_mode?platform=RESTful
EX: {
"cname": "httpClient463224",
"uid": "527841",
"clientRequest":{
"resourceExpiredHour": 24,
"scene": 1
}
}
You forgot to put "resourceExpiredHour": 24,"scene": 1
More info:
PHP: you need to put strval function
$body = ["cname"=>strval($cname),"uid" =>strval($uid),"clientRequest" => ["resourceExpiredHour" => 24,"scene" => 1]];
I hope you solve your issue

Invalid CSRF when logging in to keystone

I'm entirely new to coding. I've looked around a bit, but not found anything relevant.
When logging into keystone to view our mongoDB database I get an error message saying:
Something went wrong; please refresh your browser and try again.
Doing that does not help. Neither does deleting the browser history or attempting from another lap top.
Looking at the javascript console in the browser, the error states invalid csrf.
I think this is the relevant source code in the keystone folder:
handleSubmit (e) {
e.preventDefault();
// If either password or mail are missing, show an error
if (!this.state.email || !this.state.password) {
return this.displayError('Please enter an email address and password to sign in.');
}
xhr({
url: `${Keystone.adminPath}/api/session/signin`,
method: 'post',
json: {
email: this.state.email,
password: this.state.password,
},
headers: assign({}, Keystone.csrf.header),
}, (err, resp, body) => {
if (err || body && body.error) {
return body.error === 'invalid csrf'
? this.displayError('Something went wrong; please refresh your browser and try again.')
: this.displayError('The email and password you entered are not valid.');
} else {
// Redirect to where we came from or to the default admin path
if (Keystone.redirect) {
top.location.href = Keystone.redirect;
} else {
top.location.href = this.props.from ? this.props.from : Keystone.adminPath;
}
}
});
},
How can I go about solving this / debugging the error? Thanks for any help!
This usually happens when session affinity fails. Are you using default in-memory session management? Maybe, try using a database for maintaining session state.
If you use MongoDB, Try the following config setting
'session store': 'mongo',
See 'session store' section under http://keystonejs.com/docs/configuration/#options-database for more details.