Validating Oauth credentials in K6 load test script - javascript

I am trying to grab a token and pass it into the GET requests.
The below works, but it's grabbing a token every single time a request runs. Ideally I want to grab it once per run and pass it to the requests.
Any ideas on how to make that happen from the below code?
import http from "k6/http";
import { sleep } from "k6";
import { check } from "k6";
import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js";
export let options = {
insecureSkipTLSVerify: true,
noConnectionReuse: false,
vus: 5,
duration: "10s",
};
var client_id = "clientId123";
var secret = "secret123";
var scope = "scope123";
export default () => {
var body =
"grant_type=client_credentials&client_id=" +
client_id +
"&client_secret=" +
secret +
"&scope=" +
scope;
var tokenResponse = http.post( "https://login.microsoftonline.com/tenantID123/oauth2/v2.0/token", body, { headers: { ContentType: "application/x-www-form-urlencoded"}});
var result = JSON.parse(tokenResponse.body);
var token = result.access_token;
check(tokenResponse, {
'is status 200': (r) => r.status === 200
})
var resp1 = http.get("url_1", {
headers: { Authorization: `Bearer ${token}` },
});
var resp2 = http.get("url_2", {
headers: { Authorization: `Bearer ${token}` },
});
check(resp1, {
'is status 200': (r) => r.status === 200,
})
check(resp2, {
'is status 200': (r) => r.status === 200,
})
};

In k6 lifecycle there are 4 stages. You need to use the proper one for your need.
Get exactly one token for the whole test
Can use setup function
export function setup(){
var client_id = "clientId123";
var secret = "secret123";
var scope = "scope123";
var body =
"grant_type=client_credentials&client_id=" +
client_id +
"&client_secret=" +
secret +
"&scope=" +
scope;
var tokenResponse = http.post(
"https://login.microsoftonline.com/tenantID123/oauth2/v2.0/token",
body,
{ headers: { ContentType: "application/x-www-form-urlencoded" } }
);
var result = JSON.parse(tokenResponse.body);
var token = result.access_token;
return {token}
}
export default (data) => {
var token = data.token;
// Rest ...
}
Get one token for every VU (Virtual User)
Can use "init code."
// ...
var body =
"grant_type=client_credentials&client_id=" +
client_id +
"&client_secret=" +
secret +
"&scope=" +
scope;
var tokenResponse = http.post(
"https://login.microsoftonline.com/tenantID123/oauth2/v2.0/token",
body,
{ headers: { ContentType: "application/x-www-form-urlencoded" } }
);
var result = JSON.parse(tokenResponse.body);
var token = result.access_token;
export default () => {
var resp1 = http.get("url_1", {
headers: { Authorization: `Bearer ${token}` },
});
// ...
};

Related

Websocket with AppSync: Error UnsupportedOperation, unknown not supported through the realtime channel

I'm trying to send a subscription over a Websocket connection to AppSync. But when I send the request, I get the error {errorType: "UnsupportedOperation", message: "unknown not supported through the realtime channel"}
Here's my test code (yes, a little messy :) ):
let ws = undefined;
const id = 'XXX';
const region = 'YYY';
const apikey = 'ZZZ';
const host = id + '.appsync-api.' + region + '.amazonaws.com';
const url = 'wss://' + id + '.appsync-realtime-api.' + region + '.amazonaws.com';
const httpUrl = 'https://' + host + '/graphql';
function openWebsocket(){
const api_header = {
host: host,
'x-api-key': apikey,
};
// payload should be an empty JSON object
const payload = {};
const base64_api_header = btoa(JSON.stringify(api_header));
const base64_payload = btoa(JSON.stringify(payload));
const appsync_url = url + '?header=' + base64_api_header + '&payload=' + base64_payload;
return new WebSocket(appsync_url, ['graphql-ws']);
}
function runWebsocket() {
ws = openWebsocket();
/**
* Send request over websocket
* (Convenience function)
*/
const _send = (obj) => {
ws.send(JSON.stringify(obj));
};
let initializingMode = true;
ws.onopen = (e) => {
// initialization phase start:
_send({ type: 'connection_init' });
};
ws.onmessage = (e) => {
const data = JSON.parse(e.data);
if (initializingMode) {
if (data.type == 'connection_ack') {
// Acknowledge came, so we can start subscribing
// try to subscribe
{
const query = {
query: `subscription MySubscription {
onCreateNotifications {
creationTime
userid
}
}`,
};
const queryStr = JSON.stringify(query);
_send({
id: localStorage.getItem(HeaderItems.idToken),
type: 'start',
payload: {
data: queryStr,
},
authorization: {
host: host,
'x-api-key': apikey,
},
});
}
initializingMode = false;
return;
}
}
};
};
I think you need to put the "authorization" object inside an "extensions" property:
_send({
id: localStorage.getItem(HeaderItems.idToken),
type: 'start',
payload: {
data: queryStr,
extensions: { /* The authorization needs to be wrapped here */
authorization: {
host: host,
'x-api-key': apikey,
},
}
},
});
See: https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html - search for "Example using a custom domain name".

How do you resolve: The parameters (String) don't match the method signature for ScriptApp.getOAuthToken in Google Apps Script?

I'm trying to get information from a squareup api into Google Sheets, but I'm not quite sure how to deal with the bearer token and misalignment with the ScriptApp method signature. Thank you!
function squareLocations() {
var url = "https://connect.squareup.com/v2/locations";
var headers = {
"Square-Version": "2022-01-20",
"Authorization": token,
"Content-Type": 'application/json'
}
var data = {
'locations': {
'id': locationID,
'name': locationName,
'address': locationAdress,
}
}
const params = {
headers: head,
method: "get",
muteHttpExceptions: true,
payload: JSON.stringify(data)
}
var response = UrlFetchApp.fetch(url, headers);
var responseCode = response.getResponseCode();
var responseBody = JSON.parse(response.getContextText());
var json = JSON.parse(responseBody);
if (responseCode === 200)
{
responseJSON.error = false;
return responseJSON;
}
else
{
responseJSON.error = true;
responseJSON.message = `Request failed. Expected 200, got ${responseCode}: ${responseBody}`;
return responseJSON;
}
}

Postman Pre-request Script for authorization bearer token

I'm trying to make script to generate my authentication bearer token for collections. so I don't have to pass token each time and I will Inherit auth from parent. But I don't know where I'm wrong in script, I'm not able to generate token and it giving me error
There was an error in evaluating the Pre-request Script: Error: No data, empty input at 1:1 ^
Here is my script,
var expiresOn = pm.variables.get('ExpiresOn');
if (!expiresOn || new Date(expiresOn) <= new Date()) {
var clientId = '565v7677676vfdrd';
var apiToken = '6565fdvdrdfd';
var request = {
url: 'http://.../auth/token',
method: 'POST',
header: 'Content-Type:application/Json',
body: {
mode: 'application/json',
raw: clientId + apiToken
}
};
}
};
pm.sendRequest(request, function (err, res) {
if (res !== null) {
var json = res.json();
pm.environment.set('Access_Token', json.access_token)
var expiresOn = new Date(0);
expiresOn.setUTCSeconds(json.expires_on);
pm.environment.set('ExpiresOn', expiresOn);
}
});
}
const echoPostRequest = {
url: 'https://example.com/sign_in?client_id=dbdsA8b6V6Lw7wzu1x0T4CLxt58yd4Bf',
method: 'POST',
header: 'Accept: application/json\nUser-Agent: Example/2019.10.31-release (Android 6.0.1; LGE Nexus 5)\nUDID: 1d2c7e65f34b3882f8e42ab8d6a82b4b\nContent-Type: application/json; charset=utf-8\nHost: api-mobile.example.com',
body: {
mode: 'application/json',
raw: JSON.stringify(
{
client_id:'dbdsA8b6V6Lw7wzu1x0T4CLxt58yd4Bf',
client_secret:'aBK1xbehZvrBw0dtVYNY3BuJJOuDFrYs',
auth_method:'password',
create_if_not_found:false,
credentials:{identifier:'username',password:'pass'},
signature:'2:a899cdc0'
})
}
};
var getToken = true;
if (!pm.environment.get('accessTokenExpiry') ||
!pm.environment.get('currentAccessToken')) {
console.log('Token or expiry date are missing')
} else if (pm.environment.get('accessTokenExpiry') <= (new Date()).getTime()) {
console.log('Token is expired')
} else {
getToken = false;
console.log('Token and expiry date are all good');
}
if (getToken === true) {
pm.sendRequest(echoPostRequest, function (err, res) {
console.log(err ? err : res.json());
if (err === null) {
console.log('Saving the token and expiry date')
var responseJson = res.json();
pm.environment.set('currentAccessToken', responseJson.access_token)
var expiryDate = new Date();
expiryDate.setSeconds(expiryDate.getSeconds() + responseJson.expires_in);
pm.environment.set('accessTokenExpiry', expiryDate.getTime());
}
});
}
The above example is a Postman Pre-request script to fetch access_token, and the expire time of the token. I think this example will help you to solve the issue.
Please check the console of the postman
Open Postman Console by pressing Ctrl+Alt+C on Windows (Cmd + Alt+ C on mac)
Syntax error
When running your script I got the following error:
There was an error in evaluating the Pre-request Script: SyntaxError: Unexpected token ';'
It should be something like this in order to run correctly:
var expiresOn = pm.variables.get('ExpiresOn');
if (!expiresOn || new Date(expiresOn) <= new Date()) {
var clientId = '565v7677676vfdrd';
var apiToken = '6565fdvdrdfd';
var request = {
url: 'https://api.domain.io/api/user/session',
method: 'POST',
header: 'Content-Type:application/Json',
body: {
mode: 'application/json',
raw: clientId + apiToken
}
};
}
pm.sendRequest(request, function (err, res) {
if (res !== null) {
var json = res.json();
pm.environment.set('Access_Token', json.access_token)
var expiresOn = new Date(0);
expiresOn.setUTCSeconds(json.expires_on);
pm.environment.set('ExpiresOn', expiresOn);
}
});
Additional options
I used one of these two options to get the bearer token for my collection:
https://gist.github.com/bcnzer/073f0fc0b959928b0ca2b173230c0669#file-postman-pre-request-js
https://community.postman.com/t/how-to-automatically-set-a-bearer-token-for-your-postman-requests/10126/2
A bit modified Sebin Sunny's answer tested with JWT against Azure + resource (/audience).
In headers of request use Authorization {{$randomLoremSentence}}
const echoPostRequest = {
url: 'https://login.microsoftonline.com/{tenant}/oauth2/token',
method: 'POST',
body: {
mode: 'formdata',
formdata: [
{ key: 'grant_type', value: 'client_credentials' },
{ key: 'client_Id', value: '*******************************' },
{ key: 'client_secret', value: '*******************************' },
{ key: 'resource', value: '*******************************' }
]
}
};
var getToken = true;
var token = pm.globals.get('$randomLoremSentence') || '';
var exp = pm.globals.get('accessTokenExpiry');
var exps = new Date(exp);
if (token.indexOf('Bearer ') < 0) {
console.log('Token or expiry date are missing')
} else if (exp <= (new Date()).getTime()) {
console.log('Token is expired - ${exps}')
} else {
getToken = false;
console.log(`Token ${token.substr(0,10)}...${token.substr(-5)} and expiry ${exps} date are all good`);
}
if (getToken === true) {
pm.sendRequest(echoPostRequest, function (err, res) {
console.log(err ? err : res.json());
if (err === null) {
var responseJson = res.json();
var token = responseJson.access_token;
console.log(`Saving the token ${token.substr(0,5)}...${token.substr(-5)} and expiry ${exps} date`)
pm.globals.set('$randomLoremSentence', "Bearer " + token);
var expiryDate = new Date(responseJson.expires_on * 1000);
pm.globals.set('accessTokenExpiry', expiryDate.getTime());
}
});
}
//pm.globals.set('$randomLoremSentence', 0); // reset token 2 test

Set headers based on condition in Javascript

I am working on a react application, where i am checking for the availability of token in local storage, based on the token existence i need to set the headers.
I have tried by initially initializing the JavaScript object outside the loop and then set the headers in the if else condition.
getAllTopics() {
const token = localStorage.getItem('authKey');
var config = {};
if(token){
const URL = API_URL + `api/get-home-ideas-auth`;
var config = {
'Accept' : 'application/json',
'Authorization' : `Bearer ` + token
}
} else {
const URL = API_URL + `api/get-home-ideas`;
var config = {
'Accept' : 'application/json'
}
}
axios.get(URL, {headers : config})
.then(res => {
if (res.data && res.data.status === 1) {
const topics = res.data.data;
console.log(topics);
this.setState({ topics: topics, showloader:false});
}
})
.catch(e => {console.error(e); throw e;});
}
I am getting error Cannot GET /function URL()[nativecode]
This is a scoping issue, the problem is you initialize a new config variable inside the if-else blocks instead of referencing the one already defined outside of the scope. The new config variable is not accessible outside the private if-else scope. The outer config is never actually updated.
Just refer to the original config like so:
getAllTopics() {
const token = localStorage.getItem('authKey');
var config = {};
var URL = '';
if(token){
URL = API_URL + "api/get-home-ideas-auth";
config = {
'Accept' : 'application/json',
'Authorization' : `Bearer ${token}`
}
} else {
URL = API_URL + "api/get-home-ideas";
config = {
'Accept' : 'application/json'
}
}
axios.get(URL, {headers : config})
.then(res => {
if (res.data && res.data.status === 1) {
const topics = res.data.data;
console.log(topics);
this.setState({ topics: topics, showloader:false});
}
})
.catch(e => {console.error(e); throw e;});
}
getAllTopics() {
const token = localStorage.getItem('authKey');
const URL = API_URL + `api/get-home-ideas-auth`;
var config = {
'Accept' : 'application/json',
...(token && {'Authorization' : `Bearer ` + token})
}
axios.get(URL, {headers : config})
.then(res => {
if (res.data && res.data.status === 1) {
const topics = res.data.data;
console.log(topics);
this.setState({ topics: topics, showloader:false});
}
})
.catch(e => {console.error(e); throw e;});
}
Although already answered, the most clean way to do this is through interceptors:
/**
* Create an Axios Client with defaults
*/
const client = axios.create({
baseURL: API.BASE_URL,
});
/*
* Request interceptor
* Useful for refreshing token before to make a new request and get 401 responses
*/
client.interceptors.request.use(
config => {
const originalRequest = _.cloneDeep(config);
// Using lodash _.set() we avoid undefined keys in path
_.set(originalRequest, 'headers.Authorization', getAuth());
return originalRequest;
},
err => Promise.reject(err),
);

x-www-form-urlencoded post parameters (body) in frisby npm not working

I'm trying to test rest endpoint 'http://xxxxxxx/j_spring_security_check' to get authentication with frisby npm package.
I am able to work in postman, by selecting request body as 'x-www-form-urlencoded' tab and given my app credentials like key-value, its working fine as expected. But in frisby npm I am unable to set request body as 'x-www-form-urlencoded'.
I'm unable to login with this script.
Please help me in this or any other alternative suggestions would be great.
Here is my code:
var frisby7=require('frisby');
const qs = require('qs');
describe('API reference', function() {
var baseURL='http://xxxxxx/j_spring_security_check';
it('Simple Test with post url-encode form body request ', function() {
console.log("**********")
frisby7.globalSetup({
request: {
headers:{'Content-Type':'application/x-www-form-urlencoded'}
// headers: { 'X-Ms-Source':'api','X-Ms-Format':'xml','Authorization':'Basic c2hyZXlhIGdveWFsOm0jbWY4cDlMZ2ZAMU1xUTg='}
}
});
return frisby7.post(baseURL,
{
form: { j_username:'xxxx#xxxxx.com', j_password:'xxxx' }
}).then(function (res) { // res = FrisbyResponse object
console.log('status '+res.status);
console.log('body '+res.body);
//return res;
});
});
You are currently sending the object in the body as if you were using 'multipart/form-data'.
To send the request as 'application/x-www-form-urlencoded' you need to URI encode each property and then post them as a querystring
Try it like this
var objToSend = { j_username:'xxxx#xxxxx.com', j_password:'xxxx' };
var uriObj = Object.keys(objToSend).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(objToSend[key])).join('&');
var url = baseURL + '?' + uriObj
frisby7.post(url);
Try something like this:
var frisby = require("frisby");
const Joi = frisby.Joi;
var req1 = {
method: "get",
url: "pass url here",
headers : {
"Accept": "application/json",
"content-type" : "application/json",
'Authorization': 'Basic ' + Buffer.from(username + ":" + password).toString('base64') // pass username and password for //validation
},
body: {}
};
describe('spec file name', function () {
it("spec file name" + dateTime, function(){
return frisby
.setup({ request: { headers : req1.headers } })
.get(req1.url)
.expect("status", 200)
.expect("header", "Content-Type", "application/json; charset=utf-8")
.expect("jsonTypes", {
"message": Joi.string()
})
.then(function(res) {
var body = res.body;
body = JSON.parse(body);
expect(body.message).toBeDefined();
})
.then(function(res) {
var body = res.body;
body = JSON.parse(body);
var req2 = {
method: "put",
url: "pass url here",
headers : {
"Accept": "application/json",
"content-type" : "application/json",
"Authorization": "JWT " + Token // anything that you using to authenticate
},
body: {}
};
return frisby
.setup({ request: { headers : req2.headers } })
.put(req2.url)
.expect("status", 200)
.expect("header", "content-type", "application/json; charset=utf-8")
.expect("jsonTypes", {
"message": Joi.string()
})
.then(function(res) {
var body = res.body;
body = JSON.parse(body);
expect(body.message).toBeDefined();
})
});
});
});

Categories

Resources