Authentication with hapi-auth-cookie not setting session - node.js

I'm trying to set up a simple authentication with Hapijs and its plugin hapi-auth-cookie, but even though the login seems to be successful (right now it's a mock login), when I try to access other endpoints of the API, I'm still getting unauthorized exception.
Here's my server:
server.register([inert, auth], function(err){
server.auth.strategy('base', 'cookie', {
password: 'supersecretpassword', // cookie secret
cookie: 'app-cookie', // Cookie name
ttl: 24 * 60 * 60 * 1000 // Set session to 1 day
});
server.auth.default({
strategy: 'base'
});
server.route(routes.endpoints);
//Start the server
server.start(function () {
console.log('Server running at:', server.info.uri);
});
});
And here are my login and logout functions:
exports.login = {
auth: false,
validate: {
payload: {
email: joi.string().email().required(),
password: joi.string().min(2).max(200).required()
}
},
handler: function(request, reply) {
if(request.payload.email === 'guest#guest.com' && request.payload.password === 'password') {
request.auth.session.set({id: 123, email: 'guest#guest.com'});
return reply('Login Successful');
} else {
return reply(boom.unauthorized('Bad email or password'));
}
}
};
exports.logout = {
auth: false,
handler: function(request, reply) {
request.auth.session.clear();
return reply('Logout Successful!');
}
};
When I hit the login endpoint, it replies with the "Login Successful" message but, as I said, can't access other endpoints that don't have "auth: false" within its config.
Any help will be deeply appreciated.

First check if the cookie is created on the browser. After this try to set the auth object like this:
auth: {mode:'required',strategy:'base'}
Other modes are: try, optional. Set optional if it doesn't matters if user is authenticated or not. Set required to the endpoints you want only to be accessed by authenticated users.
If you want to secure routes by user roles, you will need to set a scope attribute to the user object set on the session:
request.auth.session.set({id: 123, email: 'guest#guest.com', scope:'admin'});
later on the auth object of the routes you set the scopes:
auth: {scope: ['admin']}
also set isSecure: false when you create the strategy. This way the cookie is sent to the client.

Related

How to set a cookie with Axios and ExpressJS

I want to set a cookie after logging in. This is my log in method:
(The res.cookie stuff doesn't work)
router.post("/login", (req, res) => {
const userForToken = { username: req.body.username };
const token = auth.generateAccessToken(userForToken);
axios
.post(userAPI + req.path, req.body)
.then(() => {
res.cookie("talloc_user_cookie_token", token, {
maxAge: 60 * 60 * 24 * 7,
httpOnly: true,
});
res.send({
username: req.body.username,
token: token,
});
console.log(
`✅ Succesfully logged as <<${req.body.username}>> Status Code: ${res.statusCode}`
);
})
.catch(() => {
res.sendStatus(404);
console.log("⛔ Error logging in. Status Code: ", res.statusCode);
});
});
I have been reading other questions and forums and everybody says to use { withCredentials: true }, which in my case just gets the request to not work and just catch the error. I have also saw that I'd need to add the Access-Control-Allow-Origin header in the request, but It doesn't seem to work too.
For anyone wondering, I am trying to make a double token submit, where I have a JWT token set in localStorage, and a cookie that also has that token, so whenever my app's middleware authenticates the user, it has to check whether the token is correct and also if the token in localStorage is equals to the cookie's token, because cookie's values cannot be changed, whereas in localStorage it is in fact changable.

Passport-SAML: read user information

Still a noob!
I am working on to build a Node application, and I have already setup various required end points. One of the requirements for my project is to use authentication using SAML mechanism. I am using passport-SAML for authentication in my application.
So far, I have been able to setup and use SAML strategy, and my application is able to call the idp entry point, and receive the response back from Idp.
I am unable to understand how do we access the user information returned by idp, so that I can use the SAML returned user information to create and maintain sessions.
const saml = require('passport-saml');
module.exports = function (passport, config) {
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
var samlStrategyOptions = new saml.Strategy(
{
// URL that goes from the Identity Provider -> Service Provider
callbackUrl: config.passport.saml.callback_url,
// path: config.passport.saml.path,
// URL that goes from the Service Provider -> Identity Provider
entryPoint: config.passport.saml.entryPoint,
issuer: config.passport.saml.issuer,
identifierFormat: null,
// Service Provider private key
decryptionPvk: config.passport.saml.decryptionPvk,
// Service Provider Certificate
privateCert: config.passport.saml.privateCert,
// Identity Provider's public key
cert: config.passport.saml.cert,
validateInResponseTo: false,
disableRequestedAuthnContext: true
},
function (profile, done) {
return done(null,
{
id: profile.uid,
email: profile.email,
displayName: profile.cn,
firstName: profile.givenName,
lastName: profile.sn
});
})
// module.exports.samlStrategyOptions = samlStrategyOptions ;
passport.use(samlStrategyOptions);
};
Following are my route controllers for express
router.route('/login')
.get(
passport.authenticate(config.passport.strategy,
{
successRedirect: '/',
failureRedirect: '/login'
})
);
router.route('/login/callback/')
.post(
passport.authenticate(config.passport.strategy,
{
failureRedirect: '/',
failureFlash: true
}),
function (req, res) {
res.redirect('/');
}
);
And this is a SAML snippet of properties that I recieve in response from Idp.
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">Shubham123</saml:NameID>
I was getting the same. SO I have used body-parser as middleware
// middleware to parse HTTP POST's JSON, buffer, string,zipped or raw and URL encoded data and exposes it on req.body
app.use(bodyParser.json());
// use querystring library to parse x-www-form-urlencoded data for flat data structure (not nested data)
app.use(bodyParser.urlencoded({ extended: false }));
and then you will get the profile like
{ issuer: '',
sessionIndex: '_x0P5ZeWx-ACSQAulKgVTxSquNsVdac_H',
nameID: 'auth0|5a266569083226773d5d43a9',
nameIDFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
nameQualifier: undefined,
spNameQualifier: undefined,
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': 'auth0|s9ds',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'myuser#q.com',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'myuser#q.com',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn': 'myuser#q.com',
'http://schemas.auth0.com/identities/default/provider': 'auth0',
'http://schemas.auth0.com/identities/default/connection': 'Username-Password-Authentication',
'http://schemas.auth0.com/identities/default/isSocial': 'false',
'http://schemas.auth0.com/email_verified': 'false',
'http://schemas.auth0.com/clientID': 'bZVOM5KQmhyir5xEYhLHGRAQglks2AIp',
'http://schemas.auth0.com/picture': 'https://s.gravatar.com/avatar/e85e57405a82225ff36b5af793ed287c?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fsu.png',
'http://schemas.auth0.com/nickname': 'myuser',
'http://schemas.auth0.com/identities': '[object Object]',
'http://schemas.auth0.com/updated_at': 'Mon Dec 18 2017 12:14:28 GMT+0000 (UTC)',
'http://schemas.auth0.com/created_at': 'Tue Dec 05 2017 09:22:49 GMT+0000 (UTC)',
getAssertionXml: [Function] }
and create user by extracting data like
{ id: profile["nameID"], userName: profile["http://schemas.auth0.com/nickname"] }
In order to get the user details, in your IDP's console, you have to setup the parameters in SP settings which you want the IDP to return and you'll get them in the assertion.
This is what I did in onelogin:
I'm using the node-saml passport module and I found this example very useful.
To summarize, once the SAML process is resolved, (your IdP is making a POST callback to your handler), the user data is stored in the request object. Now, if you want to get that user data, for example in any GET request, you could do the following:
app.get('/logout', function(req, res) {
console.log('logout');
console.log(req.user);
req.logout();
res.redirect(config.passport.saml.logoutCallback);
});
Where req.user contains all your user data. In the example, req.user contains the following:
{
firstName: 'local givenName',
lastName: 'local lastname',
email: 'testUser#sample.com'
}

How to create Oauth2 with graphql

I am using feathers server and I want to implement Oauth2 authentification with facebook or github strategy or whatever. But I also would like to use with graphql
But I dont know how to implement with graphql I'm using https://github.com/feathersjs/feathers-authentication-oauth2 it works as a API if I send GET request on callback url it works correctly I get token but I'd like do this with graphql as for example in LOCAL or LDAP strategy
const authentication = feathers()
authentication.configure(hooks())
.configure(rest(base).superagent(superagent))
.configure(auth({ storage: localStorage }));
RootMutation: {
signInLocal(root, {email, password}, context){
return authentication.authenticate({
strategy: 'local',
email: email,
password: password
}, context).then(data=>{
// console.log(data)
return data
})
},
signInLdap(root, {username, password}, context){
return authentication.authenticate({
strategy: 'ldap',
username: username,
password: password
}, context).then(data=>{
// console.log(data)
return data
})
}
}
I tried
RootQuery: {
signInGithub(root, data, context){
return authentication.authenticate({
strategy: 'github',
}, context).then(data=>{
console.log(data)
return data
})
}
},
But I got error
feathers-authentication:passport:authenticate 'github' authentication redirecting to https://github.com/login/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgithub
%2Fcallback&scope=user&client_id=0b786a43497059d2a28b 302 +3ms
feathers-authentication:middleware:failure-redirect Redirecting to https://github.com/login/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgithub%2Fcallback&scope=
user&client_id=0b786a43497059d2a28b after failed authentication. +7ms
Error: Unexpected end of JSON input
Thanks for any help

Get an access token to Linkedin API using email and password

Is it possible to get an access token in order to use node-linkedin package by providing credentials - user email and password? What I'm trying to do is an command line app, that can make an api calls to linkedin and write results in a text file. Thus, I'm not sending any api call results to the client.
I've been trying to do the same thing.
the simple-oauth2 module has a method for logging in via password, but I cannot seem to get it to work.
https://www.npmjs.com/package/simple-oauth2
// Set the configuration settings
const credentials = {
client: {
id: '<client-id>',
secret: '<client-secret>'
},
auth: {
tokenHost: 'https://api.linkedin.com',
authorizePath: 'https://api.linkedin.com/uas/oauth/requestToken',
tokenPath: 'https://api.linkedin.com/uas/oauth/accessToken'
}
};
// Initialize the OAuth2 Library
const oauth2 = require('simple-oauth2').create(credentials);
// Get the access token object.
const tokenConfig = {
username: 'username',
password: 'password'
};
// Callbacks
// Save the access token
oauth2.ownerPassword.getToken(tokenConfig, (error, result) => {
if (error) {
return console.log('Access Token Error', error.message);
}
const token = oauth2.accessToken.create(result);
});
I am not sure these endpoints are correct:
auth: {
tokenHost: 'https://api.linkedin.com',
authorizePath: 'https://api.linkedin.com/uas/oauth/requestToken',
tokenPath: 'https://api.linkedin.com/uas/oauth/accessToken'
}
I get a 400 bad request.

Passport-ldapauth fails to execute verify callback

Please , I have setup passport ldapauth which works fine with all parameters, the problem is if the username or password is wrong, the it does not execute further to the verify callback function at all. It just stops. Due to this I cannot give feedback to the users to indicate what is actually wrong. Is there any clue what I am missing?. This is the structure
passport.use('ldapStudent', new LdapStrategy({
usernameField: 'username',
passReqToCallback:true,
server: {
url: '..........',
bindDn: '.............',
bindCredentials: '..........',
searchBase: '..............',
searchFilter: '.............',
searchAttributes: ['givenName','sn'],
tlsOptions: {
ca: [fs.readFileSync('./ssl/server.crt', 'utf8')]
}
}
},
function (req, user, done) {
//now check from the DB if user exist
if(user){
//check if user email exist;
User.findOne({'EmailAddress': user}, function (err, userdata) {
// In case of any error, return using the done method
if (err)
return done(err);
//user exist redirect to home page and send user object to session
if (userdata) {
//userActivity(PostActivity);
console.log(userdata);
return done(null, userdata);
}else {
//new user, add them to the user model
var newUser = new User();
newUser.EmailAddress = req.body.username,
newUser.JoinedDate = Date.now(),
newUser.UserType = 'Student'
newUser.save(function (err, result) {
if (err) {
console.log('Error in Saving NewUser: ' + err);
} else {
console.log(result);
var PostActivity = {
ActivityName: req.res.__('Student Joined'),
ActivityDate: Date.now(),
UserID: result._id,
UserIP: (req.header('x-forwarded-for') || req.connection.remoteAddress ) + ' Port: ' + req.connection.remotePort
};
userActivity(PostActivity);
console.log('User Registration successful');
return done(null, newUser, req.flash('SuccessMessage', req.res.__('You have been successfully Registered')));
}
})
}
});
}else{
return done(null, false, req.flash('ValidationError', req.res.__('Wrong password and/or email address')));
}}));
This is where i actually do the login
router.post('/login', passport.authenticate('ldapStudent', {
successRedirect: '/',
failureRedirect: '/userlogin',
failureFlash: true
}));
The code works well , just as I expect, the parameters for the ldap option object are intentionally omitted.
The problem is when the user credential are not correct, the verify callback does not get executed at all and so, I can not return a flash message for the user to know what is happening
passport-ldapauth does not execute the verify callback if there is nothing to verify which is the case if the credentials are incorrect and the user is not received. This is in general how the strategies tend to work, e.g. passport-local does not execute verify callback if the username or password is missing.
Strategies, passport-ldapauth included, also usually include a (configurable) message for the failure flash. General configurable login failure messages for passport-ldapauth are listed in the documentation. Each of the messages also has a default value so even when not configured the failure flash message is set (given of course that you have flash middleware in use)
Also, you are not supposed to use req.flash() in the callback of the verify function but to supply an info message.

Resources