Please refer to the passport-oauth2 module documentation.
The Auth App provides OAuth2 authentication to client application. Here we present a simple Nodejs express server application .
The OAuth 2.0 authentication strategy authenticates users using a third-party
account and OAuth 2.0 tokens. The provider's OAuth 2.0 endpoints, as well as
the client identifier and secret, are specified as options. The approach
requires a verify
callback, which receives an access token and profile,
and calls cb
providing a user.
const express = require('express');
const expressSession = require('express-session');
const cookieParser = require('cookie-parser');
const ensure = require('ensure-login')
const PORT = process.env.PORT || 5000;
const SECRET = process.env.SECRET || 'i am your deepest secret sweetheart'
const passport = require('passport');
const OAuth2Strategy = require('passport-oauth2');
/**
* Oauth2 setup
*
* The clierntID and clientSecret must be set according to the state51__Application
* record in the platform
*
* @type {OAuth2Strategy}
*/
const oauth2Strategy = new OAuth2Strategy(
{
authorizationURL: 'https://auth.openimp.com/dialog/authorise',
tokenURL: 'https://auth.openimp.com/oauth/token',
clientID: process.env.CLIENT_ID || 'sample_client_application_id',
clientSecret: process.env.CLIENT_SECRET || 'sample_client_application_secret',
callbackURL: "/login/openimp/callback"
},
/**
* Callback that makes sure, that the identity and tokens received from the Auth App
* are acceptable for this application. If the application uses some notion of user persistence,
* then the persistent user should be retrieved from a store a return into the callback.
*/
function (accessToken, refreshToken, profile, cb) {
const user = {
username: profile.identifier,
profile,
accessToken,
refreshToken
}
return cb(null, user);
}
)
/**
* Custom function to load userProfile from the Auth App
*/
oauth2Strategy.userProfile = function(accessToken, done) {
let self = this;
this._oauth2.get('https://auth.openimp.com/api/userinfo', accessToken, function (err, body, res) {
let json;
if (err) {
if (err.data) {
try {
json = JSON.parse(err.data);
} catch (_) {}
}
return done(new Error('Failed to load user profile: ', json.toString()));
}
try {
json = JSON.parse(body);
} catch (ex) {
return done(new Error('Failed to parse user profile'));
}
done(null, json);
});
}
/**
* Inject the strategy into the passport middleware
*/
passport.use(oauth2Strategy)
/**
* what to store in the session - so far we store the whole profile. Once the system gets its own
* persistent representation of a user then it should store only the user ID in the session
*/
passport.serializeUser(function(user, done) {
return done(null, user);
});
/**
* and when restoring the session provides the ID and then the application backend (database, nosql storage,
* whatever) provides the rest. So far we only rely on the
*/
passport.deserializeUser(function(id, done) {
return done(null, id)
});
/**
* Setup the Express server
*/
const main = async () => {
const app = express();
app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
// we need session for storing user details
app.use(
expressSession({
saveUninitialized: true,
resave: true,
name: 'frontend.sid',
secret: SECRET
})
)
app.use(passport.initialize());
app.use(passport.session());
/**
* Login path
*/
app.get('/login', passport.authenticate('oauth2'))
/**
* The login callback, the user is redirected to theis callback
* from the Auth App
*/
app.get('/login/openimp/callback', passport.authenticate('oauth2', {
successRedirect: '/auth',
failureRedirect: '/error'
}))
/**
* Trivial logout and session destruction
*/
app.get('/logout', (req, res) => {
req.logout();
req.session.destroy(() => {
res.redirect('/');
})
});
app.get('/', (req, res) => {
res.send( {
title: 'Public section',
username: req.user? req.user.username : 'unknown'
})
})
/**
* here se setup an authorised namespace
*/
const authorisedNamespace = express.Router()
/**
* The ensure login middleware makes sure, that all requests to to routes in this Express Router
* must be authorised
*/
authorisedNamespace.use(
ensure.ensureLoggedIn({baseUrl: '/', redirectTo: '/login/openimp', setReturnTo: /^([^/]*|.*\/)[^.]+$/})
)
authorisedNamespace.get('/', (req, res) => {
res.send({
title: 'Authorised section',
username: req.user.username
})
});
/**
* Route with details about the user in the session
*/
authorisedNamespace.get('/user', (req, res) => {
res.send({
title: 'User information ',
username: req.user.username,
accessToken: req.user.accessToken,
profile: JSON.stringify(req.user.profile, null, 4)
})
});
// and mount it into the main app
app.use('/auth', authorisedNamespace)
app.listen(PORT, () => {
console.log('server started! Listening on port ' + PORT);
});
};
main()
.catch((err) => {
console.error(err);
});