Postman. Getting "JSONError: No data" after sending Cognito token pre-request - amazon-web-services

let tokenUrl = 'https://my.url/oauth2/token';
let scope = 'pets/read pets/updage petId/read'
let getTokenRequest = {
method: 'POST',
url: tokenUrl,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: 'Basic Base64Encode(client_id:client_secret)'}, // encoded manually beforehand
body: {
mode: 'formdata',
formdata: [
{ key: 'grant_type', value: 'client_credentials' },
{ key: 'scope', value: scope }
]
}
};
pm.sendRequest(getTokenRequest, (err, response) => {
let jsonResponse = response.json(),
newAccessToken = jsonResponse.access_token;
pm.environment.set('access_token', newAccessToken);
pm.variables.set('access_token', newAccessToken);
});
Geeks, help, please!
I have API with Cognito authorization (Client Credentials type). It work's fine in Postman with manually 'Request new Access token'. But I want to retrieve token with pre-request script. I relied on AWS documentation about token endpoint. I have
JSONError: No data, empty input at 1:1
in the console. Do you have any suggestions?

I've encountered the same problem and resolved it by setting grant_type and scope as query string in the url:
let tokenUrl = pm.variables.get("cognito-url")+ "/oauth2/token?grant_type=client_credentials&scope=' + pm.variables.get("cognito-scope");
let auth_code = btoa(pm.variables.get("cognito-client-id") + ":" + pm.variables.get("cognito-client-secret"))
let getTokenRequest = {
method: 'POST',
url: tokenUrl,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + auth_code}
};
pm.sendRequest(getTokenRequest, (err, response) => {
let jsonResponse = response.json(),
newAccessToken = jsonResponse.access_token;
pm.environment.set('access_token', newAccessToken);
pm.variables.set('access_token', newAccessToken);
});

Related

Postman pre-request script oder - does not run the requests in the order I expect

Total postman noob. I have a script (well I don't I am trying to) to do the drudge tasks of authentication and authorization which takes 2 requests:
console.log("START");
var authenticationToken;
// Identity token
var authenticationTokenRequest = {
url: 'xxxx',
method: 'POST',
timeout: 0,
header: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic xxxxx="
},
body: {
mode: 'urlencoded',
urlencoded: [
{key: "grant_type", value: "password"},
{key:"username", value: "xxxxx"},
{key:"password", value: "xxxx"},
]}
};
pm.sendRequest(authenticationTokenRequest, function (err, res) {
**console.log("01 send first request body");**
var responseJson = res.json();
console.log(responseJson);
pm.environment.set('ACCESS_TOKEN', responseJson['access_token']);
authenticationToken = responseJson['access_token'];
});
**console.log("Authentication token local var: " + authenticationToken);
console.log("Authorization token env var: " + pm.environment.get('ACCESS_TOKEN'));**
var authorizationTokenRequest = {
url: "xxxx",
method: "POST",
header: {
"Content-Type": "application/json",
"Authorization": "Bearer " + authenticationToken,
"Accept": "application/xxx+json"
},
body:{
tenantId: "xxx",
deviceId: "xxx"
}
}
pm.sendRequest(authorizationTokenRequest, function (err, res) {
**console.log("02 second request call");**
var responseJson = res.json();
pm.environment.set('ACCESS_TOKEN', responseJson['access_token']);
});
//
When I run this and look at the console, the console messages of the local vars show undefined. The console message for the second request shows in console before the first request. The second request depends on a value from the first.
What am I doing wrong? Thanks

Parsing nested elements from JSON response using a postman test script

I'm using the following Postman test script to check and log the status of a POST.
pm.environment.unset("uuid");
var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("uuid", jsonData.id);
var base = pm.request.url
var url = base + '/status?uuid=' + pm.environment.get("uuid");
var account = pm.request.headers.get("account")
var auth = pm.request.headers.get("Authorization")
pm.test("Status code is 200",
setTimeout(function() {
console.log("Sleeping for 3 seconds before next request.");
pm.sendRequest ( {
url: url,
method: 'GET',
header: {
'account': account,
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
'Authorization': auth
}
},
function (err, res) {
console.log(res.json().messageSummary);
})
},3000)
);
The script is able to make the call and retrieve the messageSummary from the response:
{
"id": "3c99af22-ea07-4f5d-bfe8-74a6074af71e",
"status": "SUCCESS",
"token": null,
"messageSummary": "[2] Records uploaded, please check errors/warnings and try again.",
"data": [
{
"ErrorCode": "-553",
"ErrorMessage": "Error during retrieving service service_id entered"
}
]
}
I'm wanting to also get the nested ErrorMessage, but so far everything I've tried comes back undefined or throws an error.
I assumed console.log(res.json().data[1].ErrorMessage) would work, but, alas, it does not.
UPDATE: arrays start with [0] not [1]...
pm.environment.unset("uuid");
var jsonData = pm.response.json();
pm.environment.set("uuid", jsonData.id);
var base = pm.request.url
var url = base + '/status?uuid=' + pm.environment.get("uuid");
var account = pm.request.headers.get("account")
var auth = pm.request.headers.get("Authorization")
setTimeout(function() {
console.log("Sleeping for 3 seconds before next request.");
pm.sendRequest ( {
url: url,
method: 'GET',
header: {
'account': account,
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
'Authorization': auth
}
},
function (err, res) {
console.log(res.json().messageSummary);
console.log(res.json().data[0].ErrorCode + ': ' + res.json().data[0].ErrorMessage)
})
},3000)
You would need to change the [1] to [0] to fix that reference.

Trying to get then send a cookie using react and fetch

I've been trying to implement some authentication component in my app for a few hours now, and I still don't understand some of the things that are happening.
Basically, I'd like to send a POST request containing some credentials to my API, which sends me a cookie back with a token if the credentials worked. Then, the cookie should be included in the headers of all future requests to my API (which I believed was automatic).
server.js (my API is a mockup for now, with JSON files)
...
app.post('/api/login', jsonParser, (req, res) => {
fs.readFile(ACCOUNTS_FILE, (err, data) => {
if (err) {
console.error(err);
process.exit(1);
}
const accounts = JSON.parse(data);
const credentials = {
email: req.body.email,
password: req.body.password,
};
var token = null;
for (var i = 0; i < accounts.length; ++i) {
const account = accounts[i];
if (account.email === credentials.email
&& account.password === credentials.password) {
token = account.token;
break;
}
}
if (token) {
res.setHeader('Set-Cookie', `access_token=${token}; Secure; HttpOnly;`);
res.json({ token });
} else {
res.json({ token: null });
}
});
});
...
app.js
...
handleConnection(e) {
e.preventDefault();
const email = this.state.email.trim();
const password = this.state.password.trim();
if (!email && !password) {
return (false);
}
fetch(loginUrl, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
credentials: 'include',
},
body: JSON.stringify(this.state),
})
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.warn(error);
});
return (true);
}
...
Now the console.log(data) always displays my token (or null if my credentials are wrong), but the cookie thing doesn't work...
See, I receive the Set-Cookie header, but I still have no cookie on my page.
And even if I managed to get the cookie, when I try to create a cookie using document.cookie = "access_token=123"; and then send the request again, my cookie doesn't go in my header like it would with a jQuery Ajaxcall :
I read here that adding credentials: 'include' would save the day, but unfortunately it didn't.
What am I missing here?
Thanks in advance!
I had the same problem and I found the answer in Peter Bengtsson's comment here: https://davidwalsh.name/fetch
If I understood, in your case the fetch should be:
fetch(loginUrl, {
credentials: 'same-origin',
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(this.state),
})

Getting a request token from Django OauthToolkit via React-Native

I am trying to optain a token from Django - OauthToolkit but I only get the "unsupported_grant_type" error:
Here is what I have writen in react-native:
async getToken (client_id, client_key, username, password) {
let response = await fetch('https://example.com/o/token/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: JSON.stringify({
'client_id': client_id,
'client_secret': client_key,
'grant_type': 'password',
'username': username,
'password': password,
})
})
let responseJson = await response.json()
var token = responseJson.error <- written to see the error (shoul be responseJson.acces_token)
this.setState({token})
}
other posts mentioned it could be an error in the headers - but it leaves me clueless right now.
After scratching my head and countless google searches, here's how I did it.
allow me to make some assuptions
Assume your backend server works fine, and any endpoints are protected.
Assume when you go to access an endpoint you get the error
"detail": "Authentication credentials were not provided."
Assume you can authenticate/get access token from postman or by sending a POST request to /o/token with the parameters
username
password
client_id
grant_type
With django-oauth-toolkit, it's crucial to send the data/body as
'Content-Type': 'application/x-www-form-urlencoded'
Note: My approach might not be neat so I welcome any constructive criticism/advise
import { AUTH_LOGIN} from 'react-admin';
var _client_id = 'xxxxxxxxx';
var _grant_type = 'password';
export default (type, params) => {
if (type === AUTH_LOGIN) {
const {username, password } = params;
let _data = "grant_type="+_grant_type+"&username="+username+"&password="+password+"&client_id="+_client_id
const request = new Request('http://localhost:8000/api/ps/o/oauth/token/', {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded',}),
body : _data,
})
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({ access_token }) => {
localStorage.setItem('token', access_token);
});
}
return Promise.resolve();
}
Finally yet importantly, /o/token returns a dictionary with key 'access_token' and not token. As such, modify your code as highlighted below
.then(({ access_token }) => {localStorage.setItem('token', access_token);});

Getting oauth2 token with Angularjs returns me No 'grant_type' included in the request

i try to get a token from my django-rest-framework api and an angularjs client.
This is how i use the get token access:
var payload = {
username: 'seb',
password: 'aa',
grant_type: 'password',
client_id: consumerKey,
client_secret: consumerSecret
};
var r = $http.post('http://localhost:8000/oauth2/access_token',
payload);
r.success(function(response){
console.log(response.token);
});
I've updated my headers like this:
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
unfortunately it returns me {"error_description": "No 'grant_type' included in the request.", "error": "invalid_request"}
playing with curl returns me the desired token :(
One would expect the payload to be able to exist as a Json object... but alas it requires formData type content. The clue was in your line
'application/x-www-form-urlencoded';
Hence OAuth provider is expecting the data as form based. So your payload would need to be this:
payload = "grant_type=password" + "&username=seb" + "&password=aa" +
"&client_id=" + consumerKey +
"&client_secret=" + consumerSecret;
This is a simple HttpService implementation I put together.
angular.module("services").factory("HttpService", ["$q", "$http", function ($q, $http) {
var httpSvc = {};
httpSvc.Url = "";
httpSvc.ContentType = "application/x-www-form-urlencoded";
httpSvc.JsonPayload = {};
//execute login
httpSvc.HttpPost = function () {
var deferred = $q.defer();
appLogger.conlog(httpSvc.JsonPayload);
//Http Post method
$http({
method: "POST",
url: httpSvc.Url,
transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
headers: {
"Content-Type": httpSvc.ContentType
},
data: httpSvc.JsonPayload //post data
}).success(function (data, status, headers, config) {
deferred.resolve({ data: data, status: status, headers: headers, config: config }); //result
}).error(function (data, status, headers, config) {
deferred.reject({ data: data, status: status, headers: headers, config: config }); //result
});
appLogger.conlog(deferred.promise);
//return the callback promise
return deferred.promise;
};
return httpSvc;
}]);
Just inject it into a module and use it like so
var oauth2Payload = {
grant_type: "password",
username: userName,
password: password,
client_id: appConfig.clientId
};
httpSvc.JsonPayload = oauth2Payload;
httpSvc.Url = sysConfig.tokenUrl;
httpSvc.HttpPost().then(function (response) {
var data = response.data;
appLogger.conlog("access_token:\r\n" + data.access_token);
appLogger.conlog("refresh_token:\r\n" + data.refresh_token);
$cookies.refresh_token = data.refresh_token;
appLogger.conlog(data);
deferred.resolve("ok");
}, function (errResponse) {
var data = errResponse.data;
appLogger.conlog(data);
deferred.resolve("error");
});