I'm trying to build isomorphic project using React, Express and isomorphic fetch (based on whatwg-fetch on client and node-fetch on server), from this common boilerplate. I'm using cookies for my access token, and credentials: 'same-origin' on front-end side to send it to GraphQL -- works pretty well.
The problem is that I can't use the same solution for server side -- node-fetch just don't support using of XMLHttpRequest cookies from the box. My fetch request is under few abstract layers from router, so I can't just use cookie value from req.
Here is my server.js code (full version):
server.get('*', async (req, res, next) => {
try {
// some presettings here..
await Router.dispatch({ path: req.path, query: req.query, context }, (state, component) => {
data.body = ReactDOM.renderToString(component);
});
res.send(template(data));
} catch (err) {
next(err);
}
});
and Route's index.js (full version):
export const action = async (state) => {
const response = await fetch('/graphql?query={me{id,email}}', {
credentials: 'same-origin',
});
const { data } = await response.json();
// ...
return <Login title={title} me={data.me} />;
};
How can I pass my token from server.js to my fetch module? Or, maybe there are some better decisions?
First off, I hope you have found an answer by now!
Secondly, cookies are really just headers. If you need to send a cookie to authorize server-side requests, you can always just create the string that you need for the cookie value and send it as a header.
For an example, take a look at how this server-side node-fetch wrapper appends saved cookies to the outbound request: https://github.com/valeriangalliat/fetch-cookie/blob/master/index.js#L17
Related
So, I am new at node and decided to create a user authentication/authorization system. Btw, I am using ejs as view engine and not any front-end framework. Everything works when I use postman to check API. Users are registered, tokens are generated while logging in and most importantly authorization also works when I manually put generated token in header (using postman). But how could I extract those tokens and put them in headers without postman? I saw some implementations using axios, fetch etc. But all of them were using front-end frameworks to do that.
Logging in users
Accessing protected route without token
Accessing protected route with token
UPDATE:
So the problem was in passport.authenticate() method and I added my personal verification method to extract cookies specifically.
const verifyJWT = (req: Request, res: Response, next: NextFunction) => {
const signedToken = req.cookies.jwt;
if (signedToken) {
jwt.verify(
signedToken,
config.PRIV_KEY,
{ algorithms: ["RS256"] },
(err: any, decodedToken: any) => {
if (err) {
// tslint:disable-next-line:no-console
console.log(err);
} else {
// tslint:disable-next-line:no-console
console.log(decodedToken);
next();
}
}
);
} else {
res.send("Unathorized");
}
};
You don't have to use frameworks but you do need to use javascript. Whatever you do with postman you can do using fetch or axios, you can save the tokens in your cookie.
my api call isn't sending to the proxy url domain. I know that it isn't calling as the console.log in the server isn't going off. Could someone please help me?
//client package.json
"proxy":"http://localhost:3001"
//client app
useEffect(() => {
const apicall = async () => {
try{
const response = await fetch("/")
if (response.status !== 200){
throw new Error()
}
else{
console.log("api call was success")
console.log(response)
}
} catch(error){
console.log(error)
}}
apicall()
}, [])
//server
app.get("*", (req,res)=>{
console.log("apicalled")
res.cookie("refreshToken", 987654321, {
maxAge: 60000,
httpOnly: true
})
res.send("has cookie sent?")
})
Don't have an answer for you, but it looks like you're using create-react-app? I think if you've setup your own server, you don't need to set the proxy in your package.json.
I am running a small react app and trying to access an external api behind my company's proxies. I continue to get the cors error - I've tried setting a proxy in package.json and using setupProxy.js (separately), but haven't had any luck.
I am running a React app with an Express server back-end on port:5000. I am making a request to one of my endpoint using the state of the element to get some data and then render it to the page. I initially setup the proxy in the package.json file of the React app as "proxy": "http://localhost:5000" (documentation. Now it was giving me a proxy error saying cannot proxy to localhost:5000. So I used CORS in my express server as a universal middleware for all of the routes using app.use(cors()).That removed the proxy error but the request is still not working (the code is not even reaching the endpoint because nothing is being logged to the console) and I am pretty sure it's because of the same error. Here are the code snippets
router.get("/", async (req, res) => {
var elements = [];
elements = await Element.find();
res.json(elements);
});
const getElements = async () => {
try {
console.log('getElements call')
const data = await axios.get("/api/elements");
console.log(data);
dispatch({ type: GET_ELEMENTS, payload: data });
} catch (e) {
console.error(e);
}
};
const { getElements, elements, loading } = elementContext;
useEffect(() => {
getElements();
}, [])
Expected behaviour: I want the endpoint to send an array name elements to the call which can then be set to the elements state using the reducer and then can be accessed by destructing in the end. I hope I have given adequate information. Any help will be appreciated. Thank you.
i am login from localhost use react to another localhost use express,
Hi Guys im using this code to post the login data via react:
handleSubmit(event) {
event.preventDefault();
var params = Object.entries(this.state).map(([key, val]) => `${key}=${val}`).join('&')
fetch("http://localhost:3006/login", {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'},
body: params
})
.then((response) => response.json())
.then((responseJson) => {
//this.props.history.push("/landing");
console.log("loggedin", responseJson);
})
}
and the other localhost the backend is :
router.post("/login", passport.authenticate("local",{successRedirect: "/landing",failureRedirect: "login"}) ,function(req, res){
console.log(req.body);
});
i need way to save my login data after i sent it so i can login to the page /landing.
normaly the code work when i remove the middleware.isLoggedIn from the landing page
router.get("/landing",middleware.isLoggedIn, function(req, res) {
so is there is any expert in react can help me to do it :)
One way to save user data (user session) is "WebTokens". Yow can use JsonWebToken to let the server recognize the user and know some data about him. This data is hashed and stored with the cookies in the browser. Any query from the browser (the client) to the server will be carrying this data and the server will read it and use any useful data.
For more info on how to use it with your express server take a deeper look at this example.
There is examples about how to access FeathersJS API from SSR, but they lack any info on how it is supposed to authorize such requests.
Is it ok to instantiate feathers-client app for every request? Would not it be to heavy?
There is an official example of how to call feathers API from server side:
// Set up a socket connection to our remote API
const socket = io('http://api.feathersjs.com');
const api = client().configure(socketio(socket));
app.get('/messages', function(req, res, next){
api.service('messages')
.find({ query: {$sort: { updatedAt: -1 } } })
.then(result => res.render('message-list', result.data))
.catch(next);
});
But what if the messages service will require authenticated user?
Should i just manually get token from SSR's req and add it somehow to api instance or api.service call?
Taking in mind the asynchronous nature of node it seems that durable way here is to call client() inside the app.get '/messages' handler, is it a supposed way?
It is also unclear does one of the Feathers boilerplate examples have durable SSR authentication, i've described it here.
Here is how i got it working.
On every request SSR create an API adapter before routing:
app.use('/', (req, res, next) => {
req.api = APIClient(req);
next();
});
APIClient constructor gets token from cookie an sets it using the set('accessToken', token) method, provided by feathers-authentication-client plugin:
'use strict';
const feathers = require('feathers');
const superagent = require('superagent');
const hooks = require('feathers-hooks')
const feathers_rest = require('feathers-rest/client');
const auth_plugin = require('feathers-authentication-client');
const config = require('../config');
const host = clientUrl => (
__SERVER__ ? `http://${config.apiHost}:${config.apiPort}` : clientUrl
);
/* API adaptor constructor.
*/
module.exports = function APIClient(req) {
const api = feathers()
// REST plugin gives ability to query services over HTTP,
// superagent used as an isomorphic HTTPClient.
.configure(feathers_rest(host('/api')).superagent(superagent))
.configure(hooks())
// Auth plugin gives ability to set accessToken
.configure(auth_plugin())
;
if (__SERVER__) {
api.set('accessToken', req['cookies']['feathers-jwt']);
}
return api;
}
So, here is a page loading flow i've got:
When one type 'my-app.com' in a browser, it sends a GET request to SSR, passing an access token in feathers-jwt cookie.
SSR creates a feathers client, fetches access token from the cookie and gives it to the client by api.set('accessToken', token) method.
SSR gets data from API using this client and gives it to the template engine (pug/react etc).
SSR returns rendered page to the browser.
Also one need to set token in browser when making requests to API, because if it is on another domain there will be no cookie, and it is better to use Authorization header or token parameter when accessing API.
Discussion link.