i have a nextjs app and I'm using expressjs and graphql in backend.
On my ssr page I'm doing:
export async function getServerSideProps(ctx) {
const id = ctx.query.slug[1]
const ad = await fetchCarAd(id, ctx)
return {
props: {
.
.
.
},
}
}
fetchCarAd finally goes here:
const response = await axios(getGraphqlUrl, {
data: data,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
withCredentials: true,
})
in backend i'm doing:
const canBookmarkAd = async (parent, args, context) => {
const user = await ejectUserFromReq(context)
.
.
.
}
export const ejectUserFromReq = async (context) => {
const token = context.cookies && context.cookies.token ? context.cookies.token : null
if (!!!token) {
return null
}
.
.
.
}
Here cookies is empty even when i can see the cookie in chrome developer tools > application > storage or when i navigate to this page from other next pages.
but if i eject cookie from nextjs context and pass to axios as header, it works fine.
// here ctx is comming from nextjs.
const cookie = ctx ? ctx.req.headers.cookie : null;
const response = await axios(getGraphqlUrl, {
data: data,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'CSRF-Token': getCsrfTokenFromDom(),
'Cookie': cookie || ''
},
withCredentials: true,
})
this solution works but gives us the following error:
because cookie is a forbidden headername
this happens only in getServerSideProps. if i send request after that cookies work fine and there is no need to add cookie to headername.
Anyone knows why cookies are empty or what is the correct way to send cookies in getServerSideProps?.
Related
I am new to using Axios configuration. **So I am wondering if it is possible to set axios header dynamically?**
Because the end points I am calling right now need a Authentication and different authentication for different api, so I want make a change to the created axios instance’s header when token is expired and with different URL.
Here is my current code:
in config.js
import axios from 'axios'
// to get Authorization for api_1
const {access_token_1} = axios.get('url/access_token_1')
// to get Authorization for api_2
const {access_token_2} = axios.get('url/access_token_2')
export const instance = axios.create({
headers: { Authorization: `Bearer ${access_token_1}` },
})
My Api_1 and 2 call
//Api_1
export const getCountry = async (country: string) => {
const response = await instance.get(
`/sas/${country}`
)
return response.data
}
//Api_2
export const getCity = async (city: string) => {
const response = await instance.get(
`/sps/${city}`
)
return response.data
}
I know header can be set again by certain method, but how could I set it again only when it’s expired and set the instance with right authentication for certain Api
Have a look at this documentation, you can create/update headers and pass them to your axios instance. I think this examples might help a little
axios.defaults.baseURL = 'https://api.example.com';
// Important: If axios is used with multiple domains, the AUTH_TOKEN will be sent to all of them.
// See below for an example using Custom instance defaults instead.
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
axios.get('https://example.com/getSomething', {
headers: {
Authorization: 'Bearer ' + token //the token is a variable which holds the token
}
})
So i been trying to get access to the reddit api.
I registered to reddit. verified my mail. opened an app and got my credentials.
Followed this official documentation and also came across to this tutorial
All my efforts have failed and don't get any respond.
I am using nodejs. but also tried in postman and failed.
Tried 2 options using fetch and using axios:
const axios = require('axios');
const fetch = require('node-fetch')
const { URLSearchParams } = require('url')
class RedditApi {
clientId2 = "get ur own credentials by opening an app here https://www.reddit.com/prefs/apps";
clientSecret2 = "get ur own credentials by opening an app here https://www.reddit.com/prefs/apps";
authenticationUrl = `https://www.reddit.com/api/v1/access_token`;
BASE_URL = 'https://www.reddit.com/';
tokenAuth = null;
tokenExpirationTime = null;
currencyObj = null;
constructor(currencyObj) {
this.currencyObj = currencyObj;
console.log("constructor service")
}
async getAuthToken() {
const bodyParams = new URLSearchParams({
grant_type: "https://oauth.reddit.com/grants/installed_client",
device_id: "DO_NOT_TRACK_THIS_DEVICE"
});
console.log(this.clientId2, 'this.clientId');
debugger;
const headersObj = {
'Authorization': `Basic ${Buffer.from(`${this.clientId2}:`).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded',
};
let response = null;
try {
response = await axios.post(this.authenticationUrl,
bodyParams,
{
headers: headersObj
});
debugger;
} catch (error) {
debugger;
console.error(error);
console.log(error.stack);
return null;
}
}
async getAuthToken2() {
try {
// Creating Body for the POST request which are URL encoded
const params = new URLSearchParams()
params.append('grant_type', 'https://www.reddit.com/api/v1/access_token')
params.append('device_id', 'DO_NOT_TRACK_THIS_DEVICE')
// Trigger POST to get the access token
const tokenData = await fetch('https://oauth.reddit.com/grants/installed_client', {
method: 'POST',
body: params,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${Buffer.from(`${this.clientId2}:`).toString('base64')}` // Put password as empty
}
}).then(res => {
debugger;
return res.text()
})
debugger;
if (!tokenData.error) {
debugger;
res.send(trendingResult)
}
res.status(tokenData.error).send(tokenData.message)
} catch (error) {
debugger;
console.log(error)
}
}
}
module.exports = RedditApi;
when using axios i get this respond: "Request failed with status code 401"
When using fetch i get this respond: "'403 Forbidden\nRequest forbidden by administrative rules.\n\n'"
Anybody knows what is the problem and how can i fix it?
Many thanks!
I'm using sveltekit set-cookie in an endpoint but I'm unable to figure out how to set more than one cookie. I get three cookies back from expressjs server. I need to set the three of them in my endpoint.
I have this endpoint in sveltekit that fetch from an expressjs
import cookie from 'cookie';
export async function post (event) {
const info = await event.request.json()
let email = info.name
let password = info.password
let fetchresults = ""
//fetch from expressjs//
const letscookie = async () => {
let res = await fetch('http://localhost:3000/testcookie',{
method: 'POST',
credentials : 'include',
headers: {
'Accept': 'application/json',
'Content-type' : 'application/json',
},
body: JSON.stringify({
username : email,
password : password
})
})
const data = await res.json()
fetchresults = data
return data
}
let cookieresults = await letscookie()
return {
headers : {
"loginjs-cookieone" : fetchresults.accesstoken,
"loginjs-cookietwo" : fetchresults.refreshtoken,
"x-custom-header": "Whatever",
'set-cookie': cookie.serialize("loginjs", " setcookie_in_loginjs_headers")
},
body : {
//passthistofront,
//results,
cookieresults
}
}
}
My question is how to setup more than one cookie in my headers? if I do
headers : {
"loginjs-cookieone" : fetchresults.accesstoken,
"loginjs-cookietwo" : fetchresults.refreshtoken,
"x-custom-header": "Whatever",
'set-cookie': cookie.serialize("loginjs", " setcookie_in_loginjs_headers"),
'set-cookie' : [cookie.serealize("cookieone", "valueone"), cookie.serealize("cookietwo", "valuetwo")]
},
I get the last cookie set and anything before it is ignored or over written.
So how do I set more than one cookie in my headers using set-cookie?
I removed other set-cookie lines.
Just one set-cookie and put the cookies in an array like this
'set-cookie' : [cookie.serealize("cookieone", "valueone"), cookie.serealize("cookietwo", "valuetwo")]
One set-cookie in headers.
I'm building a NextJS app, and I'm trying the access a cookie so I can use it to set a Http Header for GraphQL Request, I am using apollo-link-context. This is the code to create the ApolloClient
function createApolloClient(initialState = {}) {
const httpLink = new HttpLink({ uri: `${baseUrl}/graphql`, credentials: 'same-origin', fetch })
const authLink = setContext((_, prevCtx) => {
let token = ''
if (typeof window === 'undefined') token = getCookieFromServer(authCookieName, REQ)
else token = getCookieFromBrowser(authCookieName)
return ({ headers: { 'Auth-Token': token } })
})
const client = new ApolloClient({
ssrMode: typeof window === 'undefined',
cache: new InMemoryCache().restore(initialState),
link: authLink.concat(httpLink)
})
return client
}
The issue here is that the getCookieFromServer function expects an Express Request as the second argument, so it can extract the cookie from req.headers.cookie, and I have no idea where I can get it from there.
I finally found a way. Whenever I send a request from the server (in PageComponent.getInitialProps), I set the header in the context, then I can access it from setContext:
PageComponent.getInitialProps = async (ctx) => {
...
const token = getCookieFromServer(authCookieName, ctx.req)
const { data } = await client.query({
query,
context: { headers: { 'Auth-Token': token } }
})
...
}
Then in setContext:
const authLink = setContext((_, prevCtx) => {
let headers = prevCtx.headers || {}
if (!headers['Auth-Token']) {
const token = getCookieFromBrowser(authCookieName)
headers = { ...headers, 'Auth-Token': token }
}
return ({ headers })
})
So if the header is already present in the previous context (which is the case when sent from the server), just use it. If it is not present (when sent from the browser), get the cookie from the browser and set it.
I hope it will help somebody one day.
I've got nodejs application which handles user's requests and receives cookies which i want to proxy to internal API service. How to approach this by using node-fetch?
Don't offer superagent please.
You should be able to pass along cookies by setting it in the header of your request:
const opts = {
headers: {
cookie: 'accessToken=1234abc; userId=1234'
}
};
const result = await fetch(`/some/url`, opts);
Read & write cookies like a bot
async function login() {
return fetch('<some_url>/login', {
'headers': {
'accept': '*/*',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'cookie': '',
},
'body': 'username=foo&password=bar',
'method': 'POST',
});
}
(async() => {
const loginResponse = await login();
const loginCookies = parseCookies(loginResponse);
})();
You may want to include: accept-language, user-agent, referer, accept-encoding, etc. (check a sample request on your Chrome DevTools via the Network tab)
For some reason the resulting cookies of node-fetch requests are not compatible with new requests, but we can parse them like this:
function parseCookies(response) {
const raw = response.headers.raw()['set-cookie'];
return raw.map((entry) => {
const parts = entry.split(';');
const cookiePart = parts[0];
return cookiePart;
}).join(';');
}
Pass cookies in your future requests through the same headers:
return fetch('<some_url>/dashboard', {
'headers': {
'accept': '*/*',
'cookie': parsedCookies,
},
'method': 'GET',
});
For simple, you can write a middleware which will include the cookies to global.fetch, like below.
const realFetch = fetch;
function cookieFetch(fetch, cookie) {
return (url, opts) => {
opts = opts || {};
return fetch(url, Object.assign(opts, {
headers: Object.assign(opts.headers || {}, { cookie })
}));
};
}
function middleware(req, res, next) {
const kuki = req.headers.cookie;
global.fetch = kuki ?
cookieFetch(realFetch, kuki) :
realFetch;
next();
}
module.exports = middleware;