I don't understand why express js cannot read my header.
I use vuejs + axios for send data.
I use a module for intercept request ans response for send token.
In axios module :
axios.interceptors.request.use((req) => {
req.headers.authorization = `Bearer: ${MYTOKEN}`;
return req;
});
In my server, i use nodesJS + Express with middleware :
const router = express.Router();
router.use(function timeLog(req, res, next) {
console.log(req.headers.authorization); // undefined :(
})
So req.headers do not contains key 'authorization' and console.log(req.headers.authorization); return to me 'UNDEFINED'.
I've try to put req.header.BLABLABLA. I find it but not as key.
I really don't understand.
Exemple of return with authorization :
{ host: 'localhost:5000',
connection: 'keep-alive',
'access-control-request-method': 'POST',
origin: 'http://localhost:8080',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
'access-control-request-headers': 'authorization,content-type',
accept: '*/*',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'fr-FR,fr;q=0.9,en;q=0.8,en-US;q=0.7,ru;q=0.6'
}
try this
axios.interceptors.request.use((req) => {
// req here, it's axios config, not express req'. req.headers.Authorization = Bearer: ${MYTOKEN}`;
return req;
});
Authorization => start with A Capital
You're using Axios in the wrong way.
You're trying to log headers of the Express Request, not headers of the Axios.
// server/index.js
router.use(function timeLog(req, res, next) {
console.log(req.headers.authorization); // of course this is will undefined
})
If you're doing like so, you'll get your authorization headers...
// server/index.js
import axios from 'axios'
axios.interceptors.request.use((req) => {
// `req` here, it's axios config, not express `req'.
req.headers.authorization = `Bearer: ${MYTOKEN}`;
return req;
});
router.use(function timeLog(req, res, next) {
console.log(axios.headers.authorization); // here we are
})
Related
I have a fastify backend that runs graphql server. Without authentication hook at the server, my all graphql request and subscription in my vue app works fine.
Adding jwt authentication only graphql query and mutation works but my realtime subsciption keeps giving me unauthorized 401 error.
{"type":"UnauthorizedError","message":"No Authorization was found in request.headers","stack":"UnauthorizedError: No Authorization was found in request.headers\n at lookupToken
Theres an answer online saying to override wsclient with this code, but it does not resolve my issue.
wsClient.connectionParams = () => {
return {
headers: {
Authorization: localStorage.getItem(AUTH_TOKEN) ? `Bearer ${localStorage.getItem(AUTH_TOKEN)}` : ''
}
}
}
My Setup
vue-apollo.js
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client';
// Name of the localStorage item
const AUTH_TOKEN = 'apollo-token';
// Http endpoint
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:3000/graphql';
// Config
const defaultOptions = {
// You can use `https` for secure connection (recommended in production)
httpEndpoint,
// You can use `wss` for secure connection (recommended in production)
// Use `null` to disable subscriptions
wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:3000/graphql',
// LocalStorage token
tokenName: AUTH_TOKEN,
// Enable Automatic Query persisting with Apollo Engine
persisting: false,
// Use websockets for everything (no HTTP)
// You need to pass a `wsEndpoint` for this to work
websocketsOnly: false,
// Is being rendered on the server?
ssr: false,
// Override default apollo link
// note: don't override httpLink here, specify httpLink options in the
// httpLinkOptions property of defaultOptions.
// link: myLink
// Override default cache
// cache: myCache
// Override the way the Authorization header is set
// getAuth: tokenName => {
// const token = 'Bearer ' + localStorage.getItem(AUTH_TOKEN);
// return token || '';
// },
// Additional ApolloClient options
// apollo: { ... }
// Client local data (see apollo-link-state)
// clientState: { resolvers: { ... }, defaults: { ... } }
};
// Call this in the Vue app file
export function createProvider(options = {}) {
// Create apollo client
const { apolloClient, wsClient } = createApolloClient({
...defaultOptions,
//...options,
});
wsClient.connectionParams = () => {
return {
headers: {
authorization: localStorage.getItem('apollo-token'),
},
};
};
apolloClient.wsClient = wsClient;
// Create vue apollo provider
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
$query: {
fetchPolicy: 'cache-and-network',
},
},
errorHandler(error) {
// eslint-disable-next-line no-console
console.log(
'%cError',
'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;',
error.message
);
},
});
return apolloProvider;
}
// Manually call this when user log in
export async function onLogin(apolloClient, token) {
if (typeof localStorage !== 'undefined' && token) {
localStorage.setItem(AUTH_TOKEN, token);
}
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient);
try {
await apolloClient.resetStore();
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (login)', 'color: orange;', e.message);
}
}
// Manually call this when user log out
export async function onLogout(apolloClient) {
if (typeof localStorage !== 'undefined') {
localStorage.removeItem(AUTH_TOKEN);
}
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient);
try {
await apolloClient.resetStore();
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (logout)', 'color: orange;', e.message);
}
{
console.log('%cError on cache reset (logout)', 'color: orange;', e.message);
}
}
// Install the vue plugin
Vue.use(VueApollo);
SERVER RESPONSES
When I console log the queries or mutations
{
host: 'localhost:3000',
connection: 'keep-alive',
'content-length': '205',
'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"',
accept: '*/*',
'content-type': 'application/json',
authorization: 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJiQ2RxSzIwMm1URmx5NzY4X1VMWSJ9.eyJpc3MiOiJodHRwczovL2Rldi01M3c3NXJ3Yi5hdS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NjI0NjQ0YWIyM2M0NjMwMDcwNTE0ZTY0IiwiYXVkIjpbImh0dHBzOi8vYXBpLmd1YXJkZXguY28ubnovIiwiaHR0cHM6Ly9kZXYtNTN3NzVyd2IuYXUuYXV0aDAuY29tL3VzIHByb2ZpbGUgZW1haWwifQ.e8OJDXmICjo582blGuCOCKtYOsrRcQrG8qp_ABcFqg6faMkw0xJNbJ3r0vvktBSjN9Kp93cIHlEr_ljSpZyb9roJbCShE7LXageX3wgvtq_nawQLOMTn-aC6AQqELjvgIEsuPb998hXioF0bXljdLnUy3Fi71cZby2uciqJes7iU2j5K2VuqGNLytNJc_RL9Cin7Z_7EE5J4_Djql1jtfN7boCrAMxjRIhs2EgQ_Y0DSr53WkdssBDcKfK1fk_cxksRXRFxhbKfrJSAWIdrGf6_hlVL8WdOYRNSlzi79_x0wNPGA0zzuEX458x0ffqXvBgnb7DUC_AsT2028e1tY',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
origin: 'http://localhost:8080',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:8080/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9'
}
When I console log the subscription headers I get:
{
host: 'localhost:3000',
connection: 'Upgrade',
pragma: 'no-cache',
'cache-control': 'no-cache',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
upgrade: 'websocket',
origin: 'http://localhost:8080',
'sec-websocket-version': '13',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9',
cookie: '_legacy_auth.SECRECT.is.authenticated=true; auth.is.authenticated=true',
'sec-websocket-key': 'iFNve3jfWvxmJRCsrEH+Og==',
'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits',
'sec-websocket-protocol': 'graphql-ws'
}
I'm using React for the front-end, an Express API for our back-end, and I'm experiencing an issue with accessing our cookie with Axios' PUT or POST requests.
On Postman, i need to declare the cookie i need to make my front-end authorized on connecting to my API.
I'm doing it like this on Postman's interface :
Example of passing cookie in Postman
And when i'm calling my API's requests, on Postman, with the cookie set it works and looks like this in the Postman's code snippet :
var data = JSON.stringify({
"attributes": {
"test": test
}
});
var config = {
method: 'put',
url: 'APIurl/test',
headers: {
'Authorization': 'Bearer myPersonnalToken',
'Content-Type': 'application/json',
'Cookie': 'key=theCookieINeedToGetInMyAxiosRequest'
},
data: data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
Ok so here it is working on Postman, time to make it real on my app with Axios, like this in my front-end :
var url = 'APIurl/test'
var data = {
test: test
}
var config = {
headers: {
'Authorization': "Bearer " + myPersonnalToken,
'Content-Type': 'application/json',
},
withCredentials: true,
}
axios.put(url, JSON.stringify(data), config)
.then(res => {
console.log(res)
...
})
.catch(err => {
console.log(err)
...
})
And knowing it's cross-domain, like this in my back-end :
const corsOptions = {
// I tried with * to see if I mispelled the origin, but no
origin: theOriginIWant,
credentials: true
}
app.use(cors(corsOptions))
As I read a hundred times, {withCredentials: true} should be enough to pass my cookie in my request, and my CORS options look great to me.
But when I launch my app and click the button which calls the request, this is what my devtools Network looks like :
General
Request URL: APIurl/test
Referrer Policy: strict-origin-when-cross-origin
Request Headers
Accept: application/json
Authorization: Bearer myPersonnelToken
Content-Type: application/json
Referer: myAppUrl
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Request Payload
test=test
As you can see, my cookie is missing...
A 401 error is thrown because I cannot access the API without the cookie, with the informations below :
Access to XMLHttpRequest at 'APIurl/test' from origin 'myAppUrl' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I tried everything i saw on the web, but nothing worked for me, i just can't pass the cookie i want to my PUT or POST requests, which throws an error.
I really don't understand why GET requests work, but not POST or PUT ones...
Any idea of how to fix this ?
Thanks in advance,
Hugo GB
app.use(
express.text({type: 'text/xml'}),
express.json({type: 'application/json'}),
other middlewares...) ```
Post method headers:
{
connection: 'keep-alive',
'content-length': '1082',
'content-encoding': 'gzip',
'content-type': 'text/xml',
accept: '/',
'accept-encoding': 'gzip',
origin: 'chrome-extension://sxwwwwagimdiliamlcqswqsw',
'accept-language': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7'
}
Also I have tried express.raw with a wildcard for the type, but the response
is always 400.
```express.raw({type:'*/*', inflate:true}), (req, res, next)=>{console.log(req.body); next() },```
After finding this nodejs tutorial I was able to fix it.
The key is not to use any express parser, and use vanilla nodejs instead.
app.use(
(req, res, next)=>{
let data = []
req.on('data', chunk => {
data.push(chunk)
})
req.on('end', () => {
req.body = data.toString()
});
next()
}
)
I have a Vue app consuming Express API via Axios, trying to access an authenticated route. Including the Auth token in Postman Request header, the route yields the correct json response. However, from the Vue front end, it returns the error 404 unauthorized, no token found.
here are the request headers:
Request URL: http://localhost:8000/api/groups
Request Method: GET
Status Code: 401 Unauthorized
Remote Address: [::1]:8000
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 2587
Content-Security-Policy: default-src 'none'
Content-Type: text/html; charset=utf-8
Date: Sat, 14 Sep 2019 21:47:42 GMT
X-Content-Type-Options: nosniff
X-Powered-By: Express
Provisional headers are shown
Accept: application/json, text/plain, */*
Origin: http://localhost:8080
Referer: http://localhost:8080/groups
Sec-Fetch-Mode: cors
token: Token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJ0d29AZ21haWwuY29tIiwiaWQiOjIsImV4cCI6MTU3MzY4NTI0NiwiaWF0IjoxNTY4NDk3NjQ2fQ.6zDOfTQzf4KW5ry4mJFaLXnUL7wAnHP_8W0B0JEW5DA
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
Here is the response:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>UnauthorizedError: No authorization token was found<br> at middleware (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express-jwt/lib/index.js:76:21)<br> at Layer.handle [as handle_request] (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/layer.js:95:5)<br> at next (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/route.js:137:13)<br> at Route.dispatch (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/route.js:112:3)<br> at Layer.handle [as handle_request] (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/layer.js:95:5)<br> at /Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:281:22<br> at Function.process_params (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:335:12)<br> at next (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:275:10)<br> at Function.handle (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:174:3)<br> at router (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:47:12)<br> at Layer.handle [as handle_request] (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/layer.js:95:5)<br> at trim_prefix (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:317:13)<br> at /Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:284:7<br> at Function.process_params (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:335:12)<br> at next (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/express/lib/router/index.js:275:10)<br> at jsonParser (/Users/dariusgoore/development/writerboard/writerboard-express-api/node_modules/body-parser/lib/types/json.js:110:7)</pre>
</body>
</html>
Here is the Base config for Axios (the console.log statement retrieves the correct result):
import axios from 'axios'
const token = localStorage.getItem('token')
console.log('this is the token from localStorage ls', token)
export default () => {
return axios.create({
baseURL: process.env.VUE_APP_ROOT_API,
headers: {
'Content-Type': 'application/json',
token: token,
},
validateStatus: function () {
return true;
}
})
}
Here is my cors config in Express server:
const cors = require('cors');
const app = express()
...
var corsOptions = {
origin: '*',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions));
Here is the authentication middleware that should retrieve the token (but per the console log is getting 'undefined'):
const jwt = require('express-jwt');
const getTokenFromHeaders = (req) => {
const { headers: { authorization } } = req;
console.log('this is the authorization token from the header: ', authorization);
if(authorization && authorization.split(' ')[0] === 'Token') {
return authorization.split(' ')[1];
}
return null;
};
const auth = {
required: jwt({
secret: 'secret',
userProperty: 'user',
getToken: getTokenFromHeaders,
}),
optional: jwt({
secret: 'secret',
userProperty: 'user',
getToken: getTokenFromHeaders,
credentialsRequired: false,
}),
};
module.exports = auth;
here is the express route I am trying to secure:
const express = require('express');
const auth = require('../middlewares/authenticate');
const User = require('../models/User');
const knex = User.knex();
let router = express.Router();
router.get('/', auth.required, async (req, res) => {
console.log('this is the req.user from /groups', req.user);
const userId = req.user.id
let results = await knex.raw(`SELECT users.id, users.username, groups.id, groups.name FROM users JOIN memberships ON users.id = memberships.users_id JOIN groups ON memberships.groups_id = groups.id WHERE users.id = ${userId}`);
console.log(results);
res.json(results.rows);
});
Your server has this:
const { headers: { authorization } } = req;
That appears to be looking for a header called authorization.
Your request has this:
token: Token eyJhbGciOiJIUzI1...
due to this:
headers: {
'Content-Type': 'application/json',
token: token,
},
That header is called token, not authorization.
I am trying to implement this code example here to upload an image to an S3 bucket.
My server seems to return the pre-signed URL OK, but the PUT request that follows fails with a 400 error.
Here is the server-side pre-sign code:
var s3 = new aws.S3();
var params = {
Bucket: secrets.aws.bucket,
Key: body.filename,
ContentType: body.filetype,
ACL: 'public-read'
};
s3.getSignedUrl('putObject', params, function(err, data) {
if (err) {
console.log(err);
return err;
} else {
console.log('URL sent back to client ------------------------------------');
res.status(200).send(data);
}
});
And here is the upload action client-side:
export function uploadFile(data) {
var file = data[0];
return dispatch => {
dispatch(dropFileAccepted(data));
return makeUploadRequest('post', {filename: file.name, filetype: file.type}, '/signURLforS3')
.then(function (result) {
var signedUrl = result.data;
var options = {
headers: {
'Content-Type': file.type,
'x-amz-acl': 'public-read',
'x-amz-region': 'eu-central-1'
}
};
return axios.put(signedUrl, file, options);
})
.then(function (result) {
console.log(result);
})
.catch(function (err) {
console.log(err);
});
};
}
From the network request/response headers it looks like the content-type and CORS configuration on the bucket are correctly set, but I'm unsure whether there could be an issue with needing to set the region.
or do I need some additional settings on the bucket, like a bucket policy, or specify a Signature version ?
Request URL:https://XXXXXXXXXX.s3.amazonaws.com/brand.png?AWSAccessKeyId=AKXXXXXXXXXXXX&Content-Type=image%2Fpng&Expires=1460128516&Signature=%2BooCHlrwelBYC9fMYnu01PokgWM%3D&x-amz-acl=public-read
Request Method:PUT
Status Code:400 Bad Request
Remote Address:54.231.192.36:443
Response Headers
Access-Control-Allow-Methods:PUT, POST, GET, HEAD
Access-Control-Allow-Origin:*
Access-Control-Max-Age:3000
Connection:close
Content-Type:application/xml
Date:Fri, 08 Apr 2016 15:00:17 GMT
Server:AmazonS3
Transfer-Encoding:chunked
Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-Method
x-amz-id-2:rXMCu6YD5mLrN3beBCs+kmXDGzhzrQHV2fTUTNooWXBQuPfLNOKDcArGQWRj+NLk+zo=
x-amz-region:eu-central-1
x-amz-request-id:FC181ED154
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,fr-FR;q=0.2,fr;q=0.2
Connection:keep-alive
Content-Length:16819
Content-Type:image/png
Host:XXXXXXX.s3.amazonaws.com
Origin:http://localhost:3000
Referer:http://localhost:3000/admin/blog/create
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36
x-amz-acl:public-read
x-amz-region:eu-central-1
Query String Params
AWSAccessKeyId:AKXXXXXXXX
Content-Type:image/png
Expires:1460128516
Signature:+ooCHlrwelBYu01PokgWM=
x-amz-acl:public-read
Thanks in advance for any pointers. I've been pulling my hair out over this...