passport-ci-oidc
v2.0.5
Published
Passport Authentication Strategy for IBM Security Verify (formerly known as IBM Cloud Identity) SaaS service
Downloads
16,310
Readme
passport-ci-oidc
Deprecated Notice:
This module is no longer maintained and will be removed soon. Please use other OpenID Connect standard compliant modules (for example, openid-client.)
This module provides the passport strategy for authenticating specifically with the IBM Security Verify (ISV) service.
Install
You may install the package using npm install command:
npm install passport-ci-oidc
Uninstall
To uninstall passport-ci-oidc from your system, use the npm uninstall command:
npm uninstall passport-ci-oidc
Or just delete the passport-ci-oidc directory.
Change History
- 2.0.5
- update node-jose to 2.1.0 to address a security advisory and bug fix.
- 2.0.4
- update node-jose to 2.0.0 to address a security advisory and bug fix.
- 2.0.3
- Published in NPM.
Usage
Example
Below is a simple example of what is used to configure and use the strategy.
Note 1: https://www.discoveryendpoint.com/someendpointpathhere
is a sample discovery endpoint url.
Note 2: https://1.2.3.4:443/auth/sso/callback
is a sample callback url.
const clientId = 'clientID';
const clientSecret = 'clientSecret';
const discoveryUrl = 'https://www.discoveryendpoint.com/someendpointpathhere';
const callbackUrl = 'https://1.2.3.4:443/auth/sso/callback';
const OpenIDConnectStrategy = require('passport-ci-oidc').IDaaSOIDCStrategy;
const Strategy = new OpenIDConnectStrategy({
discoveryURL : discoveryUrl,
clientID : clientId,
scope : 'email',
response_type : 'code',
clientSecret : clientSecret,
callbackURL : callbackUrl,
skipUserProfile : true
},
(iss, sub, profile, accessToken, refreshToken, params, done) => {
process.nextTick(() => {
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
done(null, profile);
});
}
);
passport.use(Strategy);
app.get('/auth/sso/callback', (req,res,next) => {
const redirect_url = req.session.originalUrl;
passport.authenticate('openidconnect', {
successRedirect: redirect_url,
failureRedirect: '/failure',
})(req,res,next);
});
app.get('/failure', (req, res) => res.send('login failed'));
app.get('/login', passport.authenticate('openidconnect', {}));
const ensureAuthenticated = (req, res, next) => {
if(!req.isAuthenticated()) {
req.session.originalUrl = req.originalUrl;
res.redirect('/login');
} else {
return next();
}
}
app.get('/hello', ensureAuthenticated, (req, res) => res.send('Hello, '+ req.user['id'] + '!'));
Configure Strategy
The strategy authenticates users using the Cloud Identity (CI) service, which includes various credentials required by the strategy, most of which are already provided by the service. Included are the client id, client secret, and discovery endpoint.
const clientId = PUT_CLIENT_ID_HERE;
const clientSecret = PUT_CLIENT_SECRET_HERE;
const discoveryUrl = PUT_DISCOVERY_ENDPOINT_URL_HERE;
const callbackUrl = PUT_CALLBACK_URL_HERE;
const OpenIDConnectStrategy = require('passport-ci-oidc').IDaaSOIDCStrategy;
const Strategy = new OpenIDConnectStrategy({
discoveryURL : discoveryUrl,
clientID : clientId,
scope : 'email',
response_type : 'code',
clientSecret : clientSecret,
callbackURL : callbackUrl,
skipUserProfile : true
},
// This is the verify callback
(iss, sub, profile, accessToken, refreshToken, params, done) => {
process.nextTick(() => {
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
done(null, profile);
});
}
);
passport.use(Strategy);
Including Local Certificates
There is an additional option in the strategy configuration, namely using specified local certificates. This option is optional as RSASSA (RS) and ECDSA (ES) based algorithms requiring the PEM encoded public key/signing certificate should be provided through the JWKS endpoint obtained from the Discovery endpoint.
However, if the user wishes to provide the certificate manually for verification instead, this can be done by enabling this option and adding the said signing certificate as a local certificate, as explained below.
You can configure the strategy to specify one or more local certificates that you want to use when requesting the access token, and subsequently the ID token. To specify a local certificate: a. Set the attribute addCAcert to true. By default, the attribute is false. b. Set the attribute CACertPathList to provide a path list to your certificates. Note that if addCAcert is false, CACertPathList is ignored.
For example:
...
issuer: issuerId,
addCACert: true,
CACertPathList: [‘/example.crt’, ‘/example2.cer’]},
...
Include your certificates in the application directory hierarchy so that they can be read when the strategy is created. When listing your certificates, specify the location relative to the application directory. For example, if your certificate example1.crt is in the application directory, list it as ‘/example1.crt’. If it is located within a subdirectory of the application directory, such as ssl, list it as ‘/ssl/example1.crt’
Callback URL
The callback URL is a requirement for the strategy.
The callback URL is the URL for the application that consumes the authentication tokens and retrieves the user profile. For example: https://1.2.3.4:443/auth/sso/callback
Code for the callback function is also required to specify what the app does after a user logs in. Using the example mentioned above, if the callback URL is https://1.2.3.4:443/auth/sso/callback
, ensure that the callback URI you specify for app.get
is auth/sso/callback
.
The path to the resource that was originally requested is stored in the req.session.originalUrl
property.
The following example shows a callback function that redirects users to the page they originally requested before they logged in. If the login fails, users are directed to the /failure
page.
app.get('/auth/sso/callback', (req,res,next) => {
const redirectUrl = req.session.originalUrl;
passport.authenticate('openidconnect', {
successRedirect: redirectUrl,
failureRedirect: '/failure',
})(req,res,next);
});
app.get('/failure', (req, res) => res.send('login failed'));
Verify Callback
The strategy requires a verify callback, which accepts various types of parameters.
By default, these are possible parameters for the verify callback:
function (iss, sub, profile, jwtClaims, accessToken, refreshToken, params, done)
function (iss, sub, profile, accessToken, refreshToken, params, done)
function (iss, sub, profile, accessToken, refreshToken, done)
function (iss, sub, profile, done)
function (iss, sub, done)
There is an optional attribute called passReqToCallback
that can be added to the strategy in order to pass the request to the verify callback. This can be done by adding it in the strategy:
...
skipUserProfile : true,
issuer : issuerId,
passReqToCallback : true},
...
Doing so will result in the same types of callbacks listed above, except each callback will be appended with the request in front:
function (req, iss, sub, profile, jwtClaims, accessToken, refreshToken, params, done)
function (req, iss, sub, profile, accessToken, refreshToken, params, done)
function (req, iss, sub, profile, accessToken, refreshToken, done)
function (req, iss, sub, profile, done)
function (req, iss, sub, done)
ensureAuthenticated()
and /login
route
The ensureAuthenticated()
method and /login
route are also required in the app.
ensureAuthenticated()
checks if the user is already authenticated. If not, the method then stores the current url as the original url that calls the authentication request. It then redirects to the /login
route, which will then start the authentication process using the configured strategy.
app.get('/login', passport.authenticate('openidconnect', {}));
const ensureAuthenticated = (req, res, next) => {
if(!req.isAuthenticated()) {
req.session.originalUrl = req.originalUrl;
res.redirect('/login');
} else {
return next();
}
}
To use ensureAuthenticated()
, please include the method in the route to your app, such as the following test example:
app.get('/hello', ensureAuthenticated, (req, res) => res.send('Hello, '+ req.user['id'] + '!'));
Test Sample
Note: Be sure that your Bluemix SSO service has been properly set up.
To test to make sure your app works properly with the Bluemix Single Sign-On service, include the following code in your app:
app.get('/hello', ensureAuthenticated, (req, res) => res.send('Hello, '+ req.user['id'] + '!'));
After including this code, try going to the /hello
route for your app after it has been successfully deployed to Bluemix.
For example: https://myapp.mybluemix.net/hello
Contact Email
Please use this email for contact if you have questions: [email protected]
Contributors
- Jared Hanson (http://www.jaredhanson.net/)
- Ciaran Jessup
- IBM
License
MIT License
Copyright (c) 2013 Jared Hanson
Copyright (c) 2010-2012 Ciaran Jessup
Copyright (c) 2019, 2020, 2021, 2022 IBM
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.