Oracle Identity Cloud Service: Integrating a Node JS Application


Options



Before You Begin

Purpose

In this tutorial, you learn to integrate a custom NodeJS application with Oracle Identity Cloud Service using PassportJS, a flexible and modular authentication middleware.

Time to Complete

90 minutes

Scope

In this tutorial, you implement SSO between Oracle Identity Cloud Service and a NodeJS application following the conceptual architecture below:

Diagram listing the components used in the NodeJS application. For more details, check the text describing the scope right after the image.
Description of this image

In this integration:

  • Identity Cloud Service acts as OAuth 2.0 and OpenID Connect authorization server, providing Single Sign-On for the NodeJS application.
  • The NodeJS application acts as a OAuth client.
  • The NodeJS application is build using the following packages:
    • https, express, and ejs: Provides a middleware framework (express), view (ejs), and encryption (https) for the application.
    • passport: Provides an authentication middleware on top of the express framework, facilitating the access control for the application. Passport supports multiple ways of authenticating your applications through modular strategies.
    • passport-oauth-oidcs: This passport strategy, created by Indranil Jha, provides passport the ability to integrate authentication with Oracle Identity Cloud Service via OAuth2 and OpenID Connect. The strategy works based on your identity cloud service settings and insulates you from the OpenID and OAuth2 authentication process.
    • express-session, cookie-parser, and body-parser: Provides supporting services for the passportjs middleware. This includes the ability to keep user sessions on the node server (express-session), provide cookies to logged users (cookie-parser), and get information from the http body (body-parser).

What Do You Need?

  • Access to Oracle Identity Cloud Service with authorization to manage applications
    (Identity Domain Administrator, Security Administrator, or Application Administrator).
  • Experience developing in Node and Express.
  • Node installed and configured in your desktop.

Important: The sample code, packages, and strategy explored in this tutorial are provided “AS IS” with no express or implied warranty for accuracy or accessibility. The sample code is intended to demonstrate the basic integration between Oracle Identity Cloud Service and custom applications and does not represent, by any means, the recommended approach nor is it intended to be used in development or productions environments.

Register a Client Application in Identity Cloud Service

In this task, you configure and activate the Node Client application in Oracle Identity Cloud Service.
During configuration, you define how Oracle Identity Cloud Service integrates with your application.

  1. In the Identity Cloud Service console, expand the Navigation Drawer , click Applications, and then click Add.
  2. Select Trusted Application.

    Tip: The UI provides information about each type of application supported by Oracle Identity Cloud Service.
  3. Enter Node Client as the Name, Node app for testing as the Description, and then click Next.
  4. Select Configure this application as a client now.

  5. On the Authorization page, select Authorization Code and enter the information according to the table. Then click Next.
  6. Application wizard - Values for the Authorization page
    Attribute Value
    Redirect URL https://localhost/return
    Logout URL https://localhost/logout
    Post Logout Redirect URL https://otn.oracle.com
  7. Click Finish.
  8. Save the Client ID and the Client Secret, and then click Close.
  9. Application Added screen in Identity Cloud Service UI - Client ID and Secret
    Description of this image
    Tip: The Client ID and Client Secret are equivalent to a credential (ID and password) that your application uses to communicate with Oracle Identity Cloud Service.
  10. Click Activate, and then click Activate Application. Oracle Identity Cloud Service displays a confirmation message.

At this point, you have the Node application registered in Identity Cloud Service with its respective client ID and a client secret.
In the next steps, you develop your Node application.

Develop a Node Application

In this task, you develop a node application. Later, you will integrate this app with Identity Cloud Service.

Important: The sample code, packages, and strategy explored in this tutorial are provided “AS IS” with no express or implied warranty for accuracy or accessibility. The sample code is intended to demonstrate the basic integration between Oracle Identity Cloud Service and custom applications and does not represent, by any means, the recommended approach nor is it intended to be used in development or productions environments.

Create the Application

  1. Launch your terminal, create your application folders and then install the node modules that are going to be used in this tutorial:
  2. mkdir passport-idcs
    cd passport-idcs
    mkdir views
    npm i express
    npm i ejs
    
  3. Create the views/home.ejs file with the following content:
  4. <!DOCTYPE html>
    <html>
    <head>
    	<title>Node JS - Integration with Identity Cloud Service</title>
    </head>
    <body>
    	<h1>Home Page</h1>
    	<% if(!isAuthenticated) { %>
    		<a href="/auth/idcs">Log In with Oracle Identity Cloud Service</a>
    	<% }else{ %>
    		<p>Hello, <%= user.name %></p>
    		<a href="logout">Logout</a>
    	<% } %>
    </body>
    </html>
  5. Create the app.js file with the following content:
  6. //BEGIN: LOAD EXPRESS AND EJS
    	var express = require('express');
    	var app = express();
    	app.set('view engine', 'ejs');
    //END: LOAD EXPRESS AND EJS
    
    //BEGIN: ENDPOINTS
    	app.get('/', function(req, res) {
    		res.render('home', {
    			isAuthenticated: req.isAuthenticated()
    		});
    	});
    //END: ENDPOINTS
    
    //BEGIN: LOAD APP LISTENER
    	var port = process.env.PORT || 80;
    	server.listen(port, function() {
    		console.log('https://localhost:' + port + '/');
    	});
    //END: LOAD APP LISTENER
  7. Launch the application:
  8. cd passport-idcs
    node app
    http://localhost:80/
  9. Open your browser and access http://localhost/. The home page will be displayed:
  10. Application home page
    Description of this image
At this point, you have a blank node application with the minimum code required and no integration with an authentication solution.
In the next section, you implement SSL/TLS in your application.

Configure SSL/TLS

In this section, you configure encryption in your application using a self-signed certificate.
Note: Encrypted communication is considered a good security practice and a requirement for OAuth 2.0 communications.

  1. Launch your terminal, and create a certificate as follows:
  2. Tip: When prompted for certificate information (such as country, state, or common name), enter a dummy data.
    openssl req -x509 -nodes -days 365 -newkey rsa:1024 -out myapp.crt -keyout myapp.key
  3. Move the myapp.crt and myapp.key under the passport-idcs folder.
  4. Open the app.js.
  5. Add the following code after the //END: LOAD EXPRESS AND EJS line:
  6. //BEGIN: LOAD FILE SYSTEM (TO OPEN CERTIFICATES) AND HTTPS
    	var fs = require('fs');
    	var https = require('https');
    	var server = https.createServer({
    		cert: fs.readFileSync('myapp.crt'),
    		key: fs.readFileSync('myapp.key')
    	}, app);
    //END: LOAD FILE SYSTEM (TO OPEN CERTIFICATES) AND HTTPS
  7. Change the port variable to 443:
  8. var port = process.env.PORT || 443;
  9. Launch the application:
  10. cd passport-idcs
    node app
    http://localhost:443/
  11. Open your browser, access https://localhost/, and then accept the certification exception. The home page will be displayed:
  12. Application home page with SSL enabled
    Description of this image
In the next section, you integrate your application with PassportJS and Identity Cloud Service.

Integrate Node Application with PassportJS and Identity Cloud Service

In this task, you integrate your node application with PassportJS and Identity Cloud Service.

  1. Launch your terminal, and install the node modules required to use passport with Identity Cloud Service:
  2. cd passport-idcs
    #For pulling information from request body
    npm i body-parser
    #For storing sessions (app-side)
    npm i express-session
    #For setting cookies (user-side)
    npm i cookie-parser
    #PassportJS module
    npm i passport 
    #PassportJS strategy for Identity Cloud Service
    npm i passport-oauth-oidcs
  3. Open the file node_modules/oauth/lib/oauth2.js file, and comment the following lines:
  4. Tip: You are commenting these lines because Identity Cloud Service passes the client id and secret variables in the request header (instead of the request body).
    //params['client_id'] = this._clientId;
    //params['client_secret'] = this._clientSecret;
  5. Open the app.js.
  6. Add the following code between the //END: LOAD FILE SYSTEM (TO OPEN CERTIFICATES) AND HTTPS and //BEGIN: ENDPOINTS lines:
  7. //BEGIN: LOAD PASSPORT DEPENDENCIES
    	//body-parser: to read credentials from request body
    	var bodyParser = require('body-parser');
    	app.use(bodyParser.urlencoded({ extended: false }));
    	//cookie-parser: to support cookies and hold session in user's browser
    	var cookieParser = require('cookie-parser');
    	app.use(cookieParser());
    	//express-session: to support sessions on server side
    	var expressSession = require('express-session');
    	app.use(expressSession({ secret: process.env.SESSION_SECRET || 'Welcome1', resave: false, saveUninitialized: false }));
    //END: LOAD PASSPORT DEPENDENCIES
    
    //BEGIN: LOAD PASSPORT ENGINE
    	var passport = require('passport');
    	app.use(passport.initialize());
    	app.use(passport.session());
    //END: LOAD PASSPORT ENGINE
    
    //BEGIN: IDCS INFORMATION
    	var idcsInfo = {
        discoveryURL: 'https://examplez.idcs.internal.oracle.com:8943/.well-known/idcs-configuration',
        clientID: 'd6c249fbbf0c437cb6990a9533691987',
        clientSecret: 'd91ec9ad-3055-4bd9-97b7-2e32a006626c',
        callbackURL: 'https://localhost/auth/idcs/callback',
        profileURL: 'https://examplez.idcs.internal.oracle.com:8943/admin/v1/Me',
        passReqToCallback: true
      };
    //END: IDCS INFORMATION
    
    //BEGIN: LOAD IDCS STRATEGY
    	var OIDCSStrategy = require('passport-oauth-oidcs').Strategy;
    	var oidcsstrgt = new OIDCSStrategy(idcsInfo,
    		function(req, accessToken, refreshToken, profile, done) {
    				req.session.idcsAccessToken = accessToken;
    				return done(null, profile);
    		}
    	);
    	passport.use('idcs', oidcsstrgt);
    //END: LOAD IDCS STRATEGY
    
    //BEGIN: USER SERIALIZATION (REQUIRED BY PASSPORTJS)
    	passport.serializeUser(function(user, done) { done(null, user); });
    	passport.deserializeUser(function(user, done) { done(null, user); });
    //END: USER SERIALIZATION (REQUIRED BY PASSPORTJS)
    
    //BEGIN: PASSPORT ENDPOINTS FOR AUTHENTICATION AND CALLBACK (LINKED TO IDCS STRATEGY)
    	app.get('/auth/idcs', passport.authenticate('idcs'));
    	app.get('/auth/idcs/callback', passport.authenticate('idcs', { successRedirect: '/', failureRedirect: '/' }));
    //END: PASSPORT ENDPOINTS FOR AUTHENTICATION AND CALLBACK (LINKED TO IDCS STRATEGY)
    Tip: The code above performs the following tasks (in sequence):
    • Load dependencies required by passport to parse body information (body-parser), generage cookies (cookie-parser), and support sessions on server side (express-session).
    • Load the passport engine.
    • Define the Identity Cloud Service settings on the idcsInfo object.
    • Load the Identity Cloud Service strategy with the alias idcs.
    • Define the user serialization (required by Passport JS to save user information in the session).
    • Define endpoints for trigger the user authentication in IDCS (auth/idcs), and to receive the Authorization code from IDCS (auth/idcs/callback).
  8. Update the idcsInfo discoveryURL, clientID, clientSecret, and profileURL with the values from your environment. For the clientID and clientSecret, use the variables obtained during the Node Application registration in Identity Cloud Service.
  9. Update the block as follows:
  10. //BEGIN: ENDPOINTS
    	app.get('/', function(req, res) {
    		res.render('home', {
    			isAuthenticated: req.isAuthenticated(),
    			user: req.user
    		});
    	});
    	app.get('/logout', function(req, res) {
    		req.logout();//method added by passport to support logout
    		res.redirect('/');
    	});
    //END: ENDPOINTS
    Tip: The new endpoints leverage passportjs native methods to confirm whether a user is authenticated and to logout a user. In addition, the home endpoint also sets the user variable for consumption.
  11. After all modifications, your app.js should look like follows:
  12. //BEGIN: LOAD EXPRESS AND EJS
    	var express = require('express');
    	var app = express();
    	app.set('view engine', 'ejs');
    //END: LOAD EXPRESS AND EJS
    
    //BEGIN: LOAD FILE SYSTEM (TO OPEN CERTIFICATES) AND HTTPS
    	var fs = require('fs');
    	var https = require('https');
    	var server = https.createServer({
    		cert: fs.readFileSync('myapp.crt'),
    		key: fs.readFileSync('myapp.key')
    	}, app);
    //END: LOAD FILE SYSTEM (TO OPEN CERTIFICATES) AND HTTPS
    
    //BEGIN: LOAD PASSPORT DEPENDENCIES
    	//body-parser: to read credentials from request body
    	var bodyParser = require('body-parser');
    	app.use(bodyParser.urlencoded({ extended: false }));
    	//cookie-parser: to support cookies and hold session in user's browser
    	var cookieParser = require('cookie-parser');
    	app.use(cookieParser());
    	//express-session: to support sessions on server side
    	var expressSession = require('express-session');
    	app.use(expressSession({ secret: process.env.SESSION_SECRET || 'Welcome1', resave: false, saveUninitialized: false }));
    //END: LOAD PASSPORT DEPENDENCIES
    
    //BEGIN: LOAD PASSPORT ENGINE
    	var passport = require('passport');
    	app.use(passport.initialize());
    	app.use(passport.session());
    //END: LOAD PASSPORT ENGINE
    
    //BEGIN: IDCS INFORMATION
    	var idcsInfo = {
        discoveryURL: 'https://examplez.idcs.internal.oracle.com:8943/.well-known/idcs-configuration',
        clientID: 'd6c249fbbf0c437cb6990a9533691987',
        clientSecret: 'd91ec9ad-3055-4bd9-97b7-2e32a006626c',
        callbackURL: 'https://localhost/auth/idcs/callback',
        profileURL: 'https://examplez.idcs.internal.oracle.com:8943/admin/v1/Me',
        passReqToCallback: true
      };
    //END: IDCS INFORMATION
    
    //BEGIN: LOAD IDCS STRATEGY
    	var OIDCSStrategy = require('passport-oauth-oidcs').Strategy;
    	var oidcsstrgt = new OIDCSStrategy(idcsInfo,
    		function(req, accessToken, refreshToken, profile, done) {
    				req.session.idcsAccessToken = accessToken;
    				return done(null, profile);
    		}
    	);
    	passport.use('idcs', oidcsstrgt);
    //END: LOAD IDCS STRATEGY
    
    //BEGIN: USER SERIALIZATION (REQUIRED BY PASSPORTJS)
    	passport.serializeUser(function(user, done) { done(null, user); });
    	passport.deserializeUser(function(user, done) { done(null, user); });
    //END: USER SERIALIZATION (REQUIRED BY PASSPORTJS)
    
    //BEGIN: PASSPORT ENDPOINTS FOR AUTHENTICATION AND CALLBACK (LINKED TO IDCS STRATEGY)
    	app.get('/auth/idcs', passport.authenticate('idcs'));
    	app.get('/auth/idcs/callback', passport.authenticate('idcs', { successRedirect: '/', failureRedirect: '/' }));
    //END: PASSPORT ENDPOINTS FOR AUTHENTICATION AND CALLBACK (LINKED TO IDCS STRATEGY)
    
    //BEGIN: ENDPOINTS
    	app.get('/', function(req, res) {
    		res.render('home', {
    			isAuthenticated: req.isAuthenticated(),
    			user: req.user
    		});
    	});
    	app.get('/logout', function(req, res) {
    		req.logout();//method added by passport to support logout
    		res.redirect('/');
    	});
    //END: ENDPOINTS
    
    //BEGIN: LOAD APP LISTENER
    	var port = process.env.PORT || 443;
    	server.listen(port, function() {
    		console.log('https://localhost:' + port + '/');
    	});
    //END: LOAD APP LISTENER

Testing the Integration

  1. Launch the application:
  2. cd passport-idcs
    node app
    http://localhost:443/
  3. Open your browser, access https://localhost/, and then accept the certification exception. The home page will be displayed:
  4. Application home page with SSL enabled
    Description of this image
  5. Click Log In with Oracle Identity Cloud Service.
  6. The Identity Cloud Service login page is displayed.
  7. Authenticate with your credentials.
  8. Authentication in Identity Cloud Service
    Description of this image
  9. After a successful authentication, Oracle Identity Cloud Service redirects you back to the sample application, which displays a welcome message with the user details in JSON format.
  10. Home page with user data loaded
    Description of this image
    This indicates that the authentication is successful.

Optional Display application for users in Identity Cloud Service

In this task, you can make Oracle Identity Cloud Service to display the Customer Quotes application under My Apps page for specific users.

  1. In the Identity Cloud Service console, expand the Navigation Drawer , click Applications, and then click Node Client.
  2. Update the fields as follows and click Save.
  3. Values for the Application page
    Attribute Value
    Application Icon Upload an image of 95x95 pixels
    Application URL https://localhost
    Display in My Apps selected
  4. In the Identity Cloud Service console, click Users.
  5. Search and select the user that you want to give access to the Node Client application. Under Access , Click Assign , select Node Client application, and then click OK.
  6. Tip: Users assigned in this page will have the Customer Quotes application exposed under My Apps.

Want to Learn More?

To learn more about how integrate Oracle Identity Cloud Service with Java Client and Resource Server applications, try the tutorials:

To learn more about the Identity Cloud Service REST APIs, explore the following tutorials and documents:

Credits

  • Developer(s): Frederico Hakamine.
  • Contributor(s): Indranil Jha and Todd Elwood.