steam passport implementation, convert from express to nestjs - javascript

I've started to convert express project to nestjs. How should it work in Nestjs. Here is working code from Express.
(Code below just redirects to steam sign-in page)
/* eslint-disable space-before-function-paren */
// Require all the installs
var express = require('express');
var passport = require('passport');
var session = require('express-session');
var passportSteam = require('passport-steam');
var SteamStrategy = passportSteam.Strategy;
var app = express();
// Let's set a port
var port = 4000;
// Spin up the server
app.listen(port, () => {
console.log('Listening, port ' + port);
});
// Set up the SteamStrategy
// Required to get data from user for sessions
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// Initiate Strategy
passport.use(
new SteamStrategy(
{
returnURL: 'http://localhost:' + port + '/api/auth/steam/return',
realm: 'http://localhost:' + port + '/',
apiKey: 'My API key',
},
function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
)
);
app.use(
session({
secret: 'Whatever_You_Want',
saveUninitialized: true,
resave: false,
cookie: {
maxAge: 3600000,
},
})
);
app.use(passport.initialize());
app.use(passport.session());
// Routes
app.get('/', (req, res) => {
res.send(req.user);
});
app.get(
'/api/auth/steam',
passport.authenticate('steam', { failureRedirect: '/' }),
function (req, res) {
res.redirect('/');
}
);
app.get(
'/api/auth/steam/return',
passport.authenticate('steam', { failureRedirect: '/' }),
function (req, res) {
res.redirect('/');
}
);
The question is how to implement same in the nestjs???
Or if I want to implement middlewares for passport lib (serializeUser, deserializeUser), how should it happen, in nest official docs I found this examples of custom middlewares
export function logger(req: Request, res: Response, next: NextFunction) {
console.log(`Request...`);
next();
};
But how I should use passport middlware

Related

Node express-session w/ passport v0.6.0 'Login sessions require session support.'

Passport is being used to log in via Discord in order to access a Dashboard. Main problem is the logout though, worked before passport v.0.6.0, but now it doesn't. req.logout(); now needs a callback function (see here) to work, but when I now access /logout
on the website I get Error: Login sessions require session support. Did you forget to use 'express-session' middleware?
settings.json
{
"website": {
"support": "https://discord.gg/xxxxxxx",
"domain": "http://localhost:5991"
},
"config": {
"port": 5991,
"callback": "http://localhost:5991/callback",
"clientID": "botId",
"secret": "OAuth2 Secret"
}
}
index.js
const express = require('express');
const url = require('url');
const path = require('path');
const ejs = require('ejs');
const passport = require('passport');
const bodyParser = require('body-parser');
const Strategy = require('passport-discord').Strategy;
const settings = require('./settings.json');
const logger = require('silly-logger');
const favicon = require('serve-favicon');
module.exports = client => {
// website config backend
const app = express();
const session = require('express-session');
const MemoryStore = require("memorystore")(session);
// middleware
app.use(session({
secret: `superdupersecret`,
store: new MemoryStore({ checkPeriod: 86400000 }),
resave: false,
saveUninitialized: false,
}));
app.use(favicon(path.join(__dirname, 'public/assets', 'favicon.ico')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true,
}));
app.use(express.json());
app.use(express.urlencoded({
extended: true,
}));
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "./views"));
// loading public
app.use('/public', express.static(__dirname + '/public'));
app.use(passport.initialize());
app.use(passport.session());
// initialize discord login
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((obj, done) => done(null, obj));
passport.use(new Strategy({
clientID: settings.config.clientID,
clientSecret: settings.config.secret,
callbackURL: settings.config.callback,
scope: ["identify", "guilds", "guilds.join"],
},
(accessToken, refreshToken, profile, done) => {
process.nextTick(()=>done(null, profile));
},
));
app.get("/login", (req, res, next) => {
if (req.session.backURL) {
// eslint-disable-next-line no-self-assign
req.session.backURL = req.session.backURL;
} else if (req.headers.referer) {
const parsed = url.parse(req.headers.referer);
if (parsed.hostname == app.locals.domain) {
req.session.backURL = parsed.path;
}
} else {
req.session.backURL = "/";
}
next();
}, passport.authenticate("discord", { prompt: null }));
app.get("/callback", passport.authenticate("discord", { failureRedirect: "/" }), async (req, res) => {
res.redirect("/dashboard");
});
app.get("/logout", (req, res, next) => {
req.session.destroy(() => {
req.logout(function(err) {
if (err) { return next(err); }
res.redirect("/");
});
});
});
const http = require('http').createServer(app);
http.listen(settings.config.port, () => {
logger.success(`Website is online on port ${settings.config.port}, ${settings.website.domain}`);
});
};
EDIT:
I found two ways that end the session:
app.get("/logout", (req, res, next) => {
req.logout(function(err) {
if (err) { return next(err); }
res.redirect("/");
});
});
app.get("/logout", (req, res, next) => {
req.session.destroy((err) => {
if (err) { return next(err); }
res.redirect("/");
});
});

Passport Js Stuck After Calling Callback Url

I tried to implement twitter strategy using PassportJS for my ExpressJS application. However, it always stuck when calling the callback URL. Twitter actually called the callback route (I tried replacing passport.authenticate() with res.json()) but somehow when I put passport.authenticate() it got stuck. What could be the problem?
server
const express = require("express");
const cors = require("cors");
const session = require("express-session");
const csrf = require("csurf");
const compression = require("compression");
const helmet = require("helmet");
const MongoStore = require("connect-mongo");
const router = require("./routes/api.routes");
const passport = require("./middlewares/passport.middleware");
const app = express();
app.use(
cors({
origin: [
"https://api.twitter.com",
],
credentials: true,
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
session({
secret: process.env.SECRET,
resave: true,
rolling: true,
saveUninitialized: true,
store: MongoStore.create({
mongoUrl: process.env.MONGODB_URI,
}),
cookie: {
// 1 hour
maxAge: 1000 * 60 * 60 * 1,
httpOnly: true,
},
})
);
app.use(passport.initialize());
app.use(passport.session());
app.use(csrf());
app.use(helmet());
app.use(compression());
app.use(router);
// error handler
app.use(function (err, req, res, next) {
if (err.code === "EBADCSRFTOKEN") {
// handle CSRF token errors here
return res.status(403).send({ message: "form tampered with" });
}
res.status(err.status || 500);
});
module.exports = app;
routes
// OAuth 1
router.route("/auth/twitter").get(passport.authenticate("twitter"));
router
.route("/auth/twitter/callback")
.get(passport.authenticate("twitter", { failureRedirect: "/error" }), (req, res) => {
// it never reached here
res.status(200).send({ msg: "success!" });
});
router.route("/error").get((req, res) => {
res.status(403).send({ msg: "authentication failed" });
});
passport config
passport.use(
new TwitterStrategy(
{
consumerKey: process.env.TWITTER_CONSUMER_KEY,
consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
callbackURL: "http://127.0.0.1:5000/auth/twitter/callback",
passReqToCallback: true
},
async function (token, tokenSecret, profile, cb) {
try {
const user = await users.upsertUser(profile.id);
return cb(null, user);
} catch (err) {
return cb(err);
}
}
)
);
passport.serializeUser((user, cb) => {
cb(null, user.email);
});
passport.deserializeUser(async (username, cb) => {
try {
const user = await users.findUserBy("email", username);
// filter out data
cb(null, user);
} catch (err) {
cb(err);
}
});

Express / Passport SAML Authentication Redirects Leading to Infinite Loop

Trying to use passport-saml connecting to ADFS.
The SAML Response is coming back with Successful status codes.
We get the following success code back:
"<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status>"
But our Passport IsAuthenicated is always generating a false.
I have listed out all of our files used for this below and would appreciate any help.
server.js file:
const express = require('express');
const http = require('http');
const path = require('path');
const passport = require('passport');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require('express-session');
const errorhandler = require('errorhandler');
var env = process.env.NODE_ENV || 'development';
const config = require('./config/config')[env];
console.log('Using configuration', config);
require('./config/passport')(passport, config);
var app = express();
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(cookieParser());
app.enable('trust proxy'); // add this line
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(session(
{
resave: true,
saveUninitialized: true,
secret: 'default',
proxy: true // add this line
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(morgan('combined'));
function ensureAuthenticated(req, res, next) {
if (//req.isAuthenticated()
true
) {
console.log('req.isAuthenticated = ' + req.isAuthenticated());
return next(); }
else{
console.log('req.isAuthenticated = ' + req.isAuthenticated());
res.redirect('/login');
}
}
app.set('port', config.app.port);
require('./config/routes')(app, config, passport);
//ensure that ensureAuthenticated is in the get function call before master build
//ie app.get('/*', ensureAuthenticated, (req, res)
app.use(express.static(path.join(__dirname, 'public')));
app.get('/*', ensureAuthenticated, (req, res) => {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
app.listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'));
});
routes.js
module.exports = function (app, config, passport) {
app.get('/', function (req, res) {
res.redirect('/home')
});
app.get('/login',
passport.authenticate(config.passport.strategy,
{
successRedirect: '/',
failureRedirect: '/login'
})
);
app.post('/',
passport.authenticate(config.passport.strategy,
{
failureRedirect: '/',
failureFlash: true
}),
function (req, res) {
res.redirect('/');
}
);
app.get('/logout', function (req, res) {
req.logout();
// TODO: invalidate session on IP
res.redirect('https://redrectsite.com/?wa=signout1.0');
});
};
config.js
module.exports = {
development: {
app: {
name: 'Passport SAML strategy example',
port: process.env.PORT || 80
},
passport: {
strategy: 'saml',
saml: {
callbackUrl: process.env.SAML_CALLBACK_URL || 'https://oursite.com',
entryPoint: process.env.SAML_ENTRY_POINT || 'https://oursite.com/adfs/ls/idpinitiatedsignon',
issuer: process.env.SAML_ISSUER || 'https://oursite.com',
identifierFormat: null,
signatureAlgorithm: 'sha256',
authnContext: 'http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows',
disableRequestedAuthnContext: true
//cert: process.env.SAML_CERT || null
}
}
}
};
passport.js
const SamlStrategy = require('passport-saml').Strategy;
module.exports = function (passport, config) {
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
passport.use(new SamlStrategy(
{
callbackUrl: config.passport.saml.callbackUrl,
entryPoint: config.passport.saml.entryPoint,
issuer: config.passport.saml.issuer,
cert: config.passport.saml.cert,
identifierFormat: config.passport.saml.identifierFormat,
signatureAlgorithm: config.passport.saml.signatureAlgorithm,
authnContext: config.passport.saml.authnContext,
disableRequestedAuthnContext: config.passport.saml.disableRequestedAuthnContext
},
function (profile, done) {
return done(null,
{
id: profile.uid,
email: profile.email,
displayName: profile.cn,
firstName: profile.givenName,
lastName: profile.sn
});
})
);
};
I had a similar issue. If you look at what isAuthenticated() does, it's actually just checking a property within the request.session object.
https://github.com/jaredhanson/passport/blob/2327a36e7c005ccc7134ad157b2f258b57aa0912/lib/http/request.js#L86
req.isAuthenticated = function() {
var property = 'user';
if (this._passport && this._passport.instance) {
property = this._passport.instance._userProperty || 'user';
}
return (this[property]) ? true : false;
};
I'm not sure if it's passport or express-session, but once you get to the authentication method, the user object is stored at request.session.passport.user so if you like, you can directly verify that it's non-null instead of using the packaged isAuthenticated() method, which seems to check the wrong path.
My code started working after changing it to the following.
if (_.get(req, 'session.passport.user', null)) {
return next();
}
(lodash _.get for easier null-checking of the nested properties)

Passport.js / Express.js Connection Refused

When I have all of my code in app.js, authenticating with Google works fine, but I tried breaking out the authentication routes in their own files and now I get a connection refused.
//authRouter.js
const express = require("express");
const authRouter = express.Router();
const SECRETS = require("../config/secrets");
const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy;
const passport = require("passport");
passport.use(new GoogleStrategy(SECRETS.google,
(accessToken, refreshToken, profile, done) => {
return done(null, profile);
})
);
authRouter.get("/google", passport.authenticate('google', { scope: ['openid email profile'] }));
authRouter.get("/google/callback",
passport.authenticate("google",
{
failureRedirect: "/login",
successRedirect: "/"
},
(req, res) => {
res.render("hello world"); //successful auth, redirect home, but res is undefined
})
)
module.exports = authRouter;
//app.js
var authConfig = require('./config/secrets'),
express = require('express'),
passport = require('passport'),
TwitterStrategy = require("passport-google-oauth").OAuth2Strategy,
SECRETS = require("./config/secrets"),
authRoutes = require("./routes/authRoutes");
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((obj, done) => {
done(null, obj);
});
//setup for previously working Google auth
// passport.use(new GoogleStrategy(
// authConfig.google,
// (accessToken, refreshToken, profile, done) => {
// return done(null, profile);
// }
// ));
var app = express();
app.set('view engine', 'hbs');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
app.use(logger('dev'));
app.use(cookieParser());
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(__dirname + '/public'));
// Application routes
app.get('/', (req, res) => {
res.render('index', {
user: req.user
});
});
app.get('/login', (req, res) => {
res.render('login', {
user: req.user
});
});
//previously working google auth
// app.get('/auth/google',
// passport.authenticate('google', { scope: ['openid email profile'] }));
// app.get('/auth/google/callback',
// passport.authenticate('google', {
// failureRedirect: '/login'
// }),
// (req, res) => {
// // Authenticated successfully
// res.redirect('/');
// });
//**registering authentication routes
app.use("/auth", authRoutes);
app.get('/account', ensureAuthenticated, (req, res) => {
res.render('account', {
user: req.user
});
});
app.get('/logout', (req, res) => {
req.logout();
res.redirect('/');
});
app.listen(process.env.PORT || 3000, () => {
console.log("Listening...");
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
}
When I visit the app in a browser where I am logged i to Google, I get a connection refused. I know the credentials are correct, and it's likely some express setup I'm missing. Any thoughts? Thanks in advance.

ExpressJS backend Server with Angular2 CLI

I am using this Express Server to authenticate users by signing in by their steam account.
everything works now as expected.
What i want to know now, is how i can integrate this to my Angular2 Project, so i can use in the HomeComponent a Login Button which calls the Express Server.
Is it better to work with an Server.js or with a Server.ts Backend Server?
and will it be visible ? if yes, where should be its destination to garantuee security ?
Im new to this, thats why im so curious :)
thanks in advance
const express = require('express');
const session = require('express-session');
const FirebaseStore = require('connect-session-firebase')(session);
const firebase = require('firebase-admin');
const firebaseinit = firebase.initializeApp({
credential: ('**************************************'),
databaseURL: '**************************************'
});
// *************************************************************************************************************
var passport = require('passport'),
util = require('util'),
SteamStrategy = require('./').Strategy;
// *************************************************************************************************************
passport.serializeUser(function(user, done) {
done(null, user);
});
// *************************************************************************************************************
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
// *************************************************************************************************************
passport.use(new SteamStrategy({
returnURL: 'http://localhost:3000/auth/steam/return',
realm: 'http://localhost:3000/',
apiKey: '**************************************'
},
function(identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
));
// *************************************************************************************************************
var app = express();
app.set('views', __dirname + '/signon/views');
app.set('view engine', 'ejs');
app.use(session({
store: new FirebaseStore({
database: firebaseinit.database()
}),
secret: 'keyboard cat',
name: 'name of session id',
resave: true,
saveUninitialized: true
}));
// *************************************************************************************************************
// *************************************************************************************************************
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(__dirname + '/../../public'));
// app.post('/auth/openid', passport.authenticate('openid'));
// *************************************************************************************************************
app.get('/auth/steam',
passport.authenticate('steam', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/');
});
// *************************************************************************************************************
app.get('/auth/steam/return',
passport.authenticate('steam', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/');
var db = firebase.database();
var ref = db.ref("/UserID");
var SteamUserID = ref.child(req.user.id);
SteamUserID.update({
Username : req.user.displayName,
UserImg : req.user.photos[2].value
});
});
// *************************************************************************************************************
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
// *************************************************************************************************************
app.get('/', function(req, res){
res.render('index', { user: req.user });
});
// *************************************************************************************************************
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { user: req.user });
});
// *************************************************************************************************************
app.listen(3000, function () {
console.log('listening on port 3000!')
})
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/');
}
console.log('Listening on port ' + app.listen);

Categories

Resources