I am new to using postman to test api. I am trying to fetch a JWT token which I can save as an environment variable in postman. I was referring to this excellent post on how to do it: jwt-postman
I have the below python code which I used before in order to fetch the jwt token.
import requests
from requests.auth import HTTPBasicAuth
import json
session=requests.Session()
client_id ="abcdef"
secret="ghijklmnop"
token_auth="https://TEST/token"
hed = {'Content-Type': 'application/x-www-form-urlencoded'}
response = session.post(token_auth,headers =hed ,data = 'grant_type=client_credentials',auth = HTTPBasicAuth(client_id,secret),verify = True)
token = json.loads(response.content)['access_token']
print(token)
How do I write the same functionality in pm.sendRequest ?
I've not been able to run this but you're going to need to do something like this:
const options = {
url: 'https://TEST/token',
method: 'POST',
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: {
mode: 'urlencoded',
urlencoded: [
{ key: "client_id", value: "abcdef" },
{ key: "client_secret", value: "ghijklmnop" },
{ key: "grant_type", value: "client_credentials" },
]
}
};
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(options, 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());
}
});
}
Related
I have a quick question. I am using Axios to send requests to the nodejs API, when I set the token in the request header the API returns "jwt must be provided". The API expects the token with a custom name attached to it - here's how far I've gotten.
Snippet of API code that sends the token on login:
const token = jwt.sign(
{
userID: result[0].userID,
firstName: result[0].firstName,
lastName: result[0].lastName,
email: result[0].email,
role: result[0].role,
// exp: Math.floor(Date.now() / 1000) + 60 * 60,
},
"HeyImaPrivateKeyyy"
);
res.json({ token });
console.log("Login Attempt", res.statusMessage, req.body);
} else {
res.status(400).send({ message: "Invalid credentials!" });
console.log("Login Attempt", res.statusMessage, req.body);
}
-- React code from here --
Response from API on successful login:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOjEsImZpcnN0TmFtZSI6IkNhbWVyb24iLCJsYXN0TmFtZSI6IkVyYXNtdXMiLCJlbWFpbCI6ImNhbWVyb25AY2xpZnRjb2xsZWdlLmNvbSIsInJvbGUiOiJzdXBlckFkbWluIiwiaWF0IjoxNjYzMzEzNTM2fQ.9R6vXn-5Vb5fj48eUJGPNUGnXMw9TXOjJCox7U36WMI"
}
Saving the token on successful login (React)
const login = async ({ email, password }) => {
const res = await api.post(
"/auth",
{
email: email, //varEmail is a variable which holds the email
password: password,
},
{
headers: {
"Content-type": "application/json",
Authorization: false,
},
}
);
const { from } = state || {};
let token = jwt(res.data.token);
setToken("x-auth-token", token); // your token
localStorage.setItem("x-auth-token", res.data.token);
localStorage.setItem("userLogged", true);
localStorage.setItem("name", token.firstName);
localStorage.setItem("role", token.role);
navigate("/auth/dashboard" || from.pathname, { replace: true });
};
Here is the React component that is trying to call the API:
const [count, setCount] = useState(null);
const token = localStorage.getItem("x-auth-token");
const studentCount = useEffect(() => {
const config = {
headers: { "x-auth-token": token },
"Content-type": "application/json",
};
api.get("/students/", {}, config).then((response) => {
setCount(response.data);
});
}, [token]);
if (!count) return null;
This is what the API is expecting on request:
export const teacher = (req, res, next) => {
const token = req.header("x-auth-token");
if (!auth && !token)
return res.status(401).send({ message: "Access denied." });
const decoded = jwt.verify(token, "DemoPrivateKey");
if (auth && ["superAdmin", "admin", "teacher"].includes(decoded.role)) {
next();
} else {
res.status(400).send({ message: "Access denied!" });
}
};
Ideally, I would like to send the token as a header on successful login, but it saves as undefined on the client (have no idea how to fix that).
If you're using Axios then, as per the doc, get method should have config parameter in second position not third one.
So maybe, simply updating api.get("/students/", {}, config) into api.get("/students/", config) should solve your issue.
Recently updated SWR - now for some reason my data is not fetching properly.
const { data: expressionsData, error: expressionsError } = useSWRImmutable(
[`dashboard/expression/get-expression-analytics?startTime=${startDate}&endTime=${endDate}`, startDate, endDate],
apiRequest
);
Using this fetching,
import firebase from "./firebase";
export async function apiRequest(path, method = "GET", data) {
const accessToken = firebase.auth().currentUser
? await firebase.auth().currentUser.getIdToken()
: undefined;
//this is a workaround due to the backend responses not being built for this util.
if (path == "dashboard/get-settings") {
return fetch(`/api/${path}`, {
method,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
body: data ? JSON.stringify(data) : undefined,
})
.then((response) => response.json())
.then((response) => {
if (response.error === "error") {
throw new CustomError(response.code, response.messages);
} else {
return response;
}
});
}
return fetch(`/api/${path}`, {
method,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
body: data ? JSON.stringify(data) : undefined,
})
.then((response) => response.json())
.then((response) => {
console.log("error", response);
if (response.status === "error") {
// Automatically signout user if accessToken is no longer valid
if (response.code === "auth/invalid-user-token") {
firebase.auth().signOut();
}
throw new CustomError(response.code, response.message);
} else {
return response.data;
}
});
}
// Create an Error with custom message and code
export function CustomError(code, message) {
const error = new Error(message);
error.code = code;
return error;
}
// Check if a indexDb database exists
export function indexedDbdatabaseExists(dbname, callback) {
const req = window.indexedDB.open(dbname);
let existed = true;
req.onsuccess = function () {
req.result.close();
if (!existed) window.indexedDB.deleteDatabase(dbname);
callback(existed);
};
req.onupgradeneeded = function () {
existed = false;
callback(existed);
};
}
Now I'm looking at this StackOverflow thread,
useSWR doesn't work with async fetcher function
And thinking I'll just remake the fetcher to be without Async. I'm just wondering why this has stopped working though in general, and if I can just keep my existing codebase.
The error is a 400 message, it only happens with this expressions API call which takes longer to load due to the amount of data I think,
xxxx/dashboard/expression/get-expression-analytics?startTime=1648183720488&endTime=1650865720488 400 (Bad Request)
with error log
These calls are working fine, they have substantly less data though.
const { data: overall, error: psychometricError } = useSWRImmutable(
`dashboard/psychometric/get-psychometric-home?starttime=infinite`,
apiRequest
);
const { data: sentimentData, error: sentimentError } = useSWRImmutable(
[`dashboard/sentiment/get-sentiment-timefilter?startTime=${startDate}&endTime=${endDate}`, startDate, endDate],
fetchSentiment
);
Made an update to the fetch call to be more readable and specifically about the URL pathway.
import firebase from './firebase';
// Create an Error with custom message and code
export function CustomError(code, message) {
const error = new Error(message);
error.code = code;
return error;
}
export async function expressionsRequest(path, method = 'GET') {
const accessToken = firebase.auth().currentUser
? await firebase.auth().currentUser.getIdToken()
: undefined;
return fetch(`/api/${path}`, {
method,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
})
.then((response) => {
if (!response.ok) {
throw `Server error: [${response.status}] [${response.statusText}] [${response.url}]`;
}
return response.json();
})
.then((receivedJson) => {
if (receivedJson.status === 'error') {
// Automatically signout user if accessToken is no longer valid
if (receivedJson.code === 'auth/invalid-user-token') {
firebase.auth().signOut();
}
throw new CustomError(receivedJson.code, receivedJson.message);
} else {
return receivedJson.data;
}
})
.catch((err) => {
console.debug('Error in fetch', err);
throw err;
});
}
Additionally, this is what the lambda function (using next API folder) looks like,
const requireAuth = require('../../_require-auth');
const { db } = require('../../_sql');
export default requireAuth(async (req, res) => {
const { uid: id } = req.user;
const startTime = Math.round(req.query.startTime * 0.001);
const endTime = Math.round(req.query.endTime * 0.001);
const parameters = [id, startTime, endTime];
//sql injection definitely possible here, need to work out better method of dealing with this.
const sqlText = `SELECT a,b,c,d,e,f,g,h,i FROM tablename WHERE a=$1 AND i BETWEEN $2 AND $3;`;
try {
const { rows } = await db.query(sqlText, parameters);
return res.status(200).json({
code: 0,
data: rows,
});
} catch (error) {
return res.status(200).json({
code: 0,
message: 'Error occurred in getting tablename',
error,
});
}
});
using postman with the same query, i.e.,
curl --location --request GET 'http://localhost:3000/api/dashboard/expression/get-expression-analytics?startTime=1648387240382&endTime=1651069240382' \
--header 'Authorization: Bearer xxxx' \
--data-raw ''
Successfully returns a response with data attached.
Based on your first code blocks, the startDate value is getting passed into the fetcher as method, and the endDate value is getting passed into the fetcher as data. This is based on the useSWR docs about passing in an array for the key argument: https://swr.vercel.app/docs/arguments#multiple-arguments
If the code you provided is correct, I'd assume the 400 is coming from trying to pass in a random value for the method option for fetch.
This should be fixed by only passing the API endpoint path into useSWR instead of an array:
const { data: expressionsData, error: expressionsError } = useSWRImmutable(
`dashboard/expression/get-expression-analytics?startTime=${startDate}&endTime=${endDate}`,
apiRequest
);
Currently, I'm trying to use my company SSO(Oauth 2.0) Service,and I pass the url to the oauth service and
then I get the url with a code to get access token from front side, and then I pass the fetch
the code from client side url to backend server with the post, and then I get the code in server
side and redirect to the other url param in server side, i can get the user's information to client and server.
However, the client side URL show the code that i sent , so I want to know how to get rid of it.
and I searched a solution that i can redirect the page to another page, but I do not know how to .
and I want to know what i was doing is right way .
Thank you in advance.i hope it's not bad explanation
this below is what i tried :
client Side
var client_id =
"client_random_id";
var state_val = "RANDOM_STATE";
var redirectURI = "http://localhost:3000";
let api_url =
"https://www.??????/oauth2.0/authorize?response_type=code&client_id=" +
client_id +
"&redirect_uri=" +
redirectURI +
"&state=" +
state_val;
const logout = `https://www.??????/oauth2.0/Logout?client_id=${client_id}&logout_redirect_uri=${redirectURI}`;
const queryParams = new URLSearchParams(window.location.search);
const [userinfo, setuserinfo] = useState();
useEffect(() => {
fetch("http://localhost:5000/create", {
method: "post",
body: queryParams,
})
.then(response => response.json())
.then(json => {
setuserinfo(json);
})
.then("<Redirect to={routes.home.path}/>")
.catch(ex => {});
});
Server Side
app.post("/create", function (req, res) {
const code = req.body.code;
res.redirect(`/callback/?code=${code}`);
});
app.get("/callback", cors(), (req, res) => {
if (req.query.code !== null && req.query.code !== undefined) {
var token_url = "https://www.?????.kr/oauth2.0/token";
var options = {
url: token_url,
method: "POST",
form: {
grant_type: "authorization_code",
client_id: client_id,
client_secret: client_secret,
redirect_uri: redirectURI,
code: req.query.code,
state: req.query.state,
},
};
request(options, function (error1, response1, body1) {
if (!error1 && response1.statusCode == 200) {
var tdata = JSON.parse(body1);
var options2 = {
url: "https://www.??????/oauth2.0/resource",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + tdata.access_token,
},
};
request(options2, function (error2, response2, body2) {
if (!error2 && response2.statusCode == 200) {
var rdata = JSON.parse(body2);
res.writeHead(200, { "Content-Type": "text/json;charset=utf-8" });
res.end(body2);
} else {
res.status(response2.statusCode).end();
console.log("error2 = " + response2.statusCode);
}
});
} else {
res.status(response1.statusCode).end();
console.log("error1 = " + response1.statusCode);
}
});
}
});
All you need is to change this part .then("<Redirect to={routes.home.path}/>")
to something like this
.then(() => {
window.location.replace("your url")
})
you could read more about replace here
Currently, I'm using sso(Oauth) service that my company has. And I'm trying to get the data from it .
And the process is like this:
when I click the button that has sso Link and client_id or something,
then the backend server get the code (URL query) and send the code(URL query) to sso and then get the token and userId or something.
and as soon as the token is sent, then website has to change to client side.
And I was trying to get the code(URL query) from node backend server.
however, I can not get the exact url which has the code(URL query),And I want to go back to the client.
So i use res.direct in node backend server.
and it's not working and I removed it so that I can know if i can get the data in client,
But the url is changed so I can't get the exact url in client server from backend.
So my question is that how should i get the exact url query from node to react?
and How can I redirect page to client side from backend ??
this is my code :
Client:
var client_id =
"clientId ??????????????";
var state_val = "RANDOM_STATE";
var redirectURI = "http://localhost:5000";
let api_url =
"https://www.ssoservice/oauth2.0/authorize?response_type=code&client_id=" +
client_id +
"&redirect_uri=" +
redirectURI +
"&state=" +
state_val;
useEffect(() => {
const apiCall = async () => {
const response = await axios.get(`http://localhost:5000`);
console.log(response);
setRedirectURL(response);
};
apiCall();
}, []);
// this is the code that i want to get the url query
return (
<a href={api_url}>
<button>
<FormatListBulletedIcon />
<p>SSO Login</p>
</button>
</a>
)
//go to sso service to get code
backend
app.get("/", cors(), (req, res) => {
// this url is what i want to get to client side
res.redirect("http://localhost:3000"); // this is not working
if (req.query.code !== null && req.query.code !== undefined) {
var token_url = "https://www.ssoservice/oauth2.0/token";
var options = {
url: token_url,
method: "POST",
form: {
grant_type: "authorization_code",
client_id: client_id,
client_secret: client_secret,
redirect_uri: redirectURI,
code: req.query.code,
state: req.query.state,
},
};
request(options, function (error1, response1, body1) {
if (!error1 && response1.statusCode == 200) {
var tdata = JSON.parse(body1);
var options2 = {
url: "https://www.ssoservicer/oauth2.0/resource",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + tdata.access_token,
},
};
request(options2, function (error2, response2, body2) {
if (!error2 && response2.statusCode == 200) {
var rdata = JSON.parse(body2);
res.writeHead(200, { "Content-Type": "text/json;charset=utf-8" });
res.end(body2);
console.log(rdata);
//this is what i want to get
} else {
res.status(response2.statusCode).end();
console.log("error2 = " + response2.statusCode);
}
});
} else {
res.status(response1.statusCode).end();
console.log("error1 = " + response1.statusCode);
}
});
}
});
I am setting the access token in my environment variable which will fetch the value from a Pre-request script that I have written and placed in my collection but when I try to run the request it gives me error saying "Message": "Response status code does not indicate success: 401 (Unauthorized)."
but to validate if my token is correct or not I have pasted it directly to the bearer token in the request (took directly from the site) then it works fine. Not sure why in the environment variable it is fetching some different kind of token due to which I am getting this unauthorised error. This token is not matching with the real token when I compared from my site.
My request:
GET:{{Url}}/api/Ids/
const echoPostRequest = {
url: pm.environment.get('tokenUrl'),
method: 'POST',
header: 'Content-Type:application/x-www-form-urlencoded',
body: {
mode: 'urlencoded',
urlencoded: [
{ key: "id", value: pm.environment.get('Id') }
]
}
};
var getToken = true;
if (!pm.environment.get('accessTokenExpiry') ||
!pm.environment.get('accessToken')) {
console.log('Token or expiry date is 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('accessToken', responseJson.access_token)
var expiryDate = new Date();
expiryDate.setSeconds(expiryDate.getSeconds() + responseJson.expires_in);
pm.environment.set('accessTokenExpiry', expiryDate.getTime());
}
});
}
Please suggest.
Thanks in advance.
can you provide what you are using to access token value or you can paste collection so that we can get more data one request