I read Hapijs's guide on cookies and tried to implement it. In my main index.js file I put the configuration as suggested:
server.state('data', {
ttl: null,
isSecure: true,
isHttpOnly: true,
encoding: 'base64json',
clearInvalid: false,
strictHeader: true
});
And then in my route I set the cookie "data" with some data to test it, like this:
{
method: 'POST',
path: '/create',
handler: function (request, reply) {
reply('hello').state('data', { firstVisit: true });
}
}
When I check under cookies in the chrome debug tool, it doesn't show the cookie. What's strange is that it does reply with hello and it doesn't output any errors either. Does anybody know what I'm doing wrong?
Thanks!
#devinivy from https://gitter.im/hapijs/hapi explained it:
isSecure tells the browser not to honor the cookie if there isn't a secured connection.
So the solution is as simple as making isSecure to false while not on HTTPS (at least for development purposes).
Related
I am building a Nuxt app that uses fastify for the backend API. I am using httpOnly session-cookies for authentication. So far everything works fine but the issue i have is that Nuxt just has a hardcoded cookie timeout of 30 minutes. I have updated this to 24hrs but what i really want to do is have Nuxt refresh the timeout after each request.
I see in my database that the fastify session cookie get updated after each request and the session expiration gets updated after ANY user API request. So, this looks like the backend is functioning correctly but the frontend need to update the auth._token_expiration.local value.
You can see in the config that i manually set the maxAge to 24hrs, cant i have the frontend update the auth._token_expiration.local value automatically when making successful API requests? my token is stored as sessionId
nuxt.config.js
auth: {
redirect: false,
strategies: {
local: {
token: {
required: false,
type: false,
maxAge: 86400 // seconds - 1 day
},
user: { property: false },
endpoints: {
login: {
url: '/user/login',
method: 'post',
withCredentials: true
},
logout: {
url: '/user/logout',
method: 'post',
withCredentials: true
},
user: {
url: '/user/profile',
method: 'get',
withCredentials: true
}
}
},
localStorage: false,
cookie: true
}
},
So i discovered that the sessionId Expires data DOES get updated after each api request, so that is good. To make this function i also had to set the nuxt.config token maxAge to 0. This solved my issues.
i have an app with Webserver implemented using Hapi JS, and whenever i opened an application with browser's tab i am able to see the cookies are injected in Request header.
but if i load my app inside third application through Iframe. there is missing cookies from the header . can you please some body help here .
Hapi JS code
server.auth.strategy('session', 'cookie', {
password: 'longpassword-should-be-32-characters-for-pulse',
cookie: 'my-app-sid',
redirectTo: '/',
ttl: 86400000,
isSecure: false,
validateFunc: isAuth
});
and my API call where the cookies missing from req header
getBookDetails = () => {
return {
auth: {
strategy: 'session'
},
handler: {
proxy: {
mapUri: (request, callback) => {
let url = 'https://mydemoapp.com'
let tokenHeaders = { token: request.auth.credentials.token,
assetid: request.headers['assetid'],
asseturl:request.headers['asseturl'],
deviceid: deviceid,
appversion: request.headers['appversion'],
'user-agent': request.headers['user-agent'],
'accept-language': request.headers['accept-language']
};
url = url + '/book/' + request.params.bookId;
callback(null, url, tokenHeaders);
},
onResponse: (err, res, request, reply) => {
wreck.read(res, { json: true, gzip: true }, (err, payload) => {
reply(payload);
});
}
}
}
}
}
i am suspecting that since my app is loaded inside the iframe of third party app. and while requesting the webserver URL mentioned above getBookDetails() it could'nt read the cookies by Iframe from the Parent app (Third party app).
can some one help please
I think the first place should be checked in your browser.
For the authentication my server (nestjs) sends back a cookie with the token.
This is done like this:
#SetCookies()
#Post("account/signin")
async signin(#Body() dto: LoginDto, #Req() req, ){
const token = await this._authService.signin(req.user);
const options: CookieOptions = {
expires: moment().add(10, "days").toDate(),
signed: false,
secure: false,
sameSite: false,
httpOnly: true,
};
req._cookies = [
{
name: "SESSIONID",
value: token,
options: options,
}
];
}
And it works! At least postman shows me that the cookie was successfully created and send back.
But when Angular calls the API like this:
public signin(dto: LoginDto): Observable<any>{
return this._httpClient.post("http://localhost:3000/account/signin", {
username: dto.username,
password: dto.password,
}, {
withCredentials: true,
})
}
The set-cookie is send back visible in the network tab of the devtools.
Chrome devtools response headers
But the cookie is not stored in on the disk. The user is logged in but no cookie is persisted. EditThisCookie shows nothing and after a reload no cookie is send when a request to the server is made.
In other questions the problem got resolved by setting the secure attribute of the cookie to false, which i already tried.
I have setup cors with credentials = true on the server, without any errors on both sides while signing in.
I use fetch() to send a post request for logon,
after server validation, I use req.session.account = account[0]; to save the account information to the session and return a redirect URL,
But after the redirect, the account information in the session is lost, why is that?
If you would have some example code, that would help us track down the problem. My first idea would be to make sure express-session is properly configured:
var app = express();
var session = require('express-session');
app.use(session({
secret: 'ibfiyegfiyegfe' // Secret is a required option.
}));
For futher configuration options, see the express-session repository.
EDIT: Based on the additional information, I'm guessing you have express-session configured to also use cookies for managing the sessions. What this means, is that for every HTTP request Express sends a response back that includes a cookie. jQuery based AJAX calls will ignore the response cookie however, which causes consecutive requests to Express to look as if you never logged in. To allow saving the cookie when performing AJAX requests with jQuery, use the xhrFields field to enable withCredentials:
$.ajax({
url: "http://....",
type: "POST",
xhrFields: {
withCredentials: true
},
data: {username: username, password: password},
success: function(responseBody) {
console.log("success!");
},
error: function(responseBody) {
console.log("error!");
}
});
Hope this helps.
Sorry to everyone, I don't making the question clear.
I use the fetch() method send a request to logon.
fetch('/logon', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
account: account,
password: password
})
}).then(function(response){
return response.json();
}).then(function(json){
if(json.success == 1){
window.location.href = json.redirecturl;
}else{
indexDispatcher.dispatch({
actionType: 'logonFaild',
errorInfo: json.msg
});
}
});
And the server's response is just simple JSON:
if (err) {
consoloe.log(err);
} else {
req.session.account = account[0]; //save account to session
var redirecturl = '/team/' + team[0].id;
console.log("account添加到session了");
res.json({
success: 1,
redirecturl: redirecturl
});
}
But when the client get the redirecturl and redirect, the account data is lost,so it will occur a TypeError: Cannot read property 'id' of undefined(id is saved in req.session.account).
But when I use jquery $.ajax relpace fetch, it works well. I don't know the reason.
I had the same experience like you hundreds of times which I finally found the problem. You don't need to worry if cookies enable or disable.
You just have to re-declare parts of your scripts (variables-the data which you want to display) in a if else condition.
Just redeclare the same thing using !isset and then else with the same variables mentioned twice in the if else condition, if you understand what i mean.
It will call back the same variables over and over. And make sure start session is above the page. no need to worry about headers or white lines, it has actually nothing to do with it.
I've tried it a million times. You don't need to bother using ajax etc. PHP can do almost everything. cheerio.
For my node app im using the bell and hapi-auth-cookie plugins to use the Yahoo api. With the current code, I am able to authenticate with Yahoo and then am redirected to the homepage. However, request.auth seems to be empty once I get to the homepage. From what I can tell, I'm doing everything exactly as the example, yet I have no authentication once I get back to the homepage. Any help is appreciated! Here's what I've got:
var Path = require('path');
var Hapi = require('hapi');
var cookieSession = require('cookie-session');
var serverOptions = {
views: {
engines: {
html: require('handlebars')
},
path: Path.join(__dirname, './app/www/public/pages'),
layoutPath: Path.join(__dirname, './app/www/public/pages')
}
};
var server = new Hapi.Server(8003, serverOptions);
server.pack.register([
require('bell'),
require('hapi-auth-cookie')
], function(err) {
if (err) {
throw err;
}
server.auth.strategy('yahoo', 'bell', {
provider: 'yahoo',
password: 'cookie_encryption_password',
clientId:'2kj3kj2',
clientSecret: '3kj2k3jl',
isSecure: false // Terrible idea but required if not using HTTPS
});
server.auth.strategy('session', 'cookie', {
password: 'secret',
cookie: 'sid-example',
redirectTo: '/login',
isSecure: false
});
server.route({
method: ['GET', 'POST'], // Must handle both GET and POST
path: '/login', // The callback endpoint registered with the provider
config: {
auth: 'yahoo',
handler: function (request, reply) {
var creds = request.auth.credentials;
request.auth.session.clear();
request.auth.session.set(creds);
return reply.redirect('/');
}
}
});
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply.view('index', { title: 'hello world' });
}
});
server.start();
});
To expound upon and extend Eran's answer:
If you want to have access to the authentication/session data for a route that doesn't need authentication to view (such as a home page) it is possible but not very intuitive in my opinion. You have to set the auth scheme on the route but then change the mode to 'try' and also set a route specific hapi-auth-cookie parameter to prevent an unauthenticated user from being redirected to the login page as such:
server.route({
method: 'GET',
path: '/',
config: {
handler: homepage,
auth: {
mode: 'try',
strategy: 'session'
},
plugins: { 'hapi-auth-cookie': { redirectTo: false } }
}
});
mode: 'try' will allow a user to proceed to the route path even if not authenticated and redirectTo: false will stop an unauthenticated request for the route being redirected to the login page. This way, users can get to this route without authentication (typical for a home page) but once authenticated the cookie data set via hapi-auth-cookie is available for use.
You home page is missing authentication. You need to configure '/' to use your cookie auth scheme.
Even with things setup correctly, I've seen issues lately with Facebook and Twitter (so I could see Yahoo doing the same) depending on which version of Bell was used (4.0 has issues with Facebook for sure) and if the calls were from node_modules or not. As crazy as that sounds, these issues can be seen in recent versions of Clapper where hapi-bell-auth-cookie-plugin works fine using the exact same approach (but not as a node_module).