Learn About Authentication Between Node.js Applications and Oracle Identity Cloud Service

You’re ready to learn about authentication between Node.js web applications and Oracle Identity Cloud Service. This includes understanding the following:

  • The three-legged authentication flow that Oracle Identity Cloud Service supports for the Node.js SDK

  • Use cases for using an SDK with a Node.js application to authenticate with Oracle Identity Cloud Service

  • Methods and functions of the Node.js SDK

Learn About Three-Legged Authentication Flows

Oracle Identity Cloud Service supports the three-legged authentication flow for the Node.js SDK. In this flow, users interact directly with Oracle Identity Cloud Service. After a user signs in, Oracle Identity Cloud Service issues an authorization code that the SDK exchanges for a user access token. The Node.js web application uses this access token to grant users access to the protected resources in the application. The three-legged flow uses the authorization code grant type.

For increased security, Oracle recommends that you use the three-legged flow to integrate your Node.js web applications with Oracle Identity Cloud Service for authentication. By using the authorization code grant type, you can also access other applications that are protected by Oracle Identity Cloud Service without having to re-authenticate.

Learn About the Primary Use Cases for Using an SDK with a Node.js Application

The Node.js web application implements two use cases: one for authenticating users, and the other for accessing detailed information about the logged-in user.

The following data flow diagrams illustrate the flow of events, calls, and responses between the web browser, the web application, and Oracle Identity Cloud Service for each use case.

Use Case #1: Authenticate a User

The data flow happens this way:

  1. The user requests a protected resource.

  2. The authentication module uses the SDK to generate a request-authorization-code URL for Oracle Identity Cloud Service and send this URL as a redirect response to the web browser.

  3. The web browser calls the URL.

  4. The Oracle Identity Cloud Service Sign In page appears.

  5. The user submits their Oracle Identity Cloud Service sign-in credentials.

  6. After the user signs in, Oracle Identity Cloud Service creates a session for the user and issues an authorization code.

  7. The web application makes a back-end (or server-to-server) call to exchange the authorization code for an access token.

  8. Oracle Identity Cloud Service issues an access token and an id token.

  9. A session is established, and the user is redirected to the Home page.

  10. The Home page of the web application appears.

Use Case #2: Get Details About the User

The data flow happens this way:

  1. The user requests the /myProfile resource.

  2. The web application uses Oracle Identity Cloud Service's SDK to validate the id token.

  3. The data that returns from id token validation contains user's details in the format of a JSON object.

  4. The My Profile page renders the JSON object as HTML content.

Learn About Methods and Functions

The Node.js SDK is a Node.js passport strategy that you add to your Node.js modules folder. This SDK is also based on Node.js promises.

All third-party dependencies that the Node.js SDK needs are defined in the SDK’s package.json file inside the Node.js SDK zip file that you download from the Oracle Identity Cloud Service console. You need to use at least this set of modules in your Node.js web application.

"dependencies": {
    "async": "^2.1.2",
    "bunyan": "^1.8.5",
    "cache-manager": "^2.2.0",
    "json-web-token": "^2.1.3",
    "jsonwebtoken": "^8.2.1",
    "jwk-to-pem": "^1.2.6",
    "jws": "^3.1.5",
    "lru": "^3.1.0",
    "passport": "^0.4.0",
    "promise": "^8.0.1",
    "querystring": "^0.2.0",
    "request": "^2.81.0",
    "rsa-pem-to-jwk": "^1.1.3",
    "util": "^0.10.3"
  },

A Node.js web application was developed using the Node.js express and express-handlebars modules, which implements URL routes in the form of an app.get() function for each URL.

The Node.js SDK requires a JSON variable that’s loaded with Oracle Identity Cloud Service connection information. The Node.js web application uses the ids variable to store this information:

var ids = {
    oracle: {
    "ClientId": "123456789abcdefghij'",
    "ClientSecret": "abcde-12345-zyxvu-98765-qwerty",
    "ClientTenant": "idcs-abcd1234",
    "IDCSHost": "https://%tenant%.identity.oraclecloud.com",
    "AudienceServiceUrl" : "https://idcs-abcd1234.identity.oraclecloud.com",
    "TokenIssuer": "https://identity.oraclecloud.com/",
    "scope": "urn:opc:idm:t.user.me openid",
    "logoutSufix": "/oauth2/v1/userlogout",
    "redirectURL": "http://localhost:3000/callback",
    "LogLevel":"INFO",
    "ConsoleLog":"True"
    }
};
module.exports = ids;

Below is a brief explanation of each required attribute for this SDK:

Name Description
ClientId The value of the Client ID that’s generated after you register the Node.js web application in the Oracle Identity Cloud Service console.
ClientSecret The value of the Client Secret that’s generated after you register the Node.js web application in the Oracle Identity Cloud Service console.
ClientTenant The domain prefix of your Oracle Identity Cloud Service instance. This prefix is usually similar to idcs-abcd1234.
IDCSHost The domain suffix of your Oracle Identity Cloud Service instance. At runtime, the %tenant% placeholder is replaced by the value of the ClientTenant attribute.
AudienceServiceUrl The fully-qualified domain name URL of your Oracle Identity Cloud Service instance.
TokenIssuer For this attribute, Oracle recommends that you keep the value https://identity.oraclecloud.com/.
scope

The scope controls the data that the application can access or process on behalf of the Oracle Identity Cloud Service user.

If the application uses the SDK to authenticate a user, then the scope is openid. If the application uses the SDK to get details about the user, then the scope is urn:opc:idm:t.user.me openid.

ConsoleLog Enables SDK log.
LogLevel Indicates the log level of the SDK.

The application uses both the logoutSufix and redirectURL attributes to avoid hard code these values. The SDK doesn’t require them.

The Node.js application implements the /oauth/oracle URL route. When a user authenticates with Oracle Identity Cloud Service, the web browser makes a GET request to this URL. This route uses the SDK to generate Oracle Identity Cloud Service's authorization URL.

//Loading the configurations
var auth = require('./auth.js');
 
//Route for /oauth/oracle
app.get("/auth/oracle", function(req, res){
    //Authentication Manager loaded with the configurations.
    am = new IdcsAuthenticationManager(auth.oracle);
    //Using Authentication Manager to generate the Authorization Code URL, passing the
    //application's callback URL as parameter, along with code value and code parameter.
    am.getAuthorizationCodeUrl(auth.oracle.redirectURL, auth.oracle.scope, "1234", "code")
        .then(function(authZurl){
            //Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
            res.redirect(authZurl);
        }).catch(function(err){
            res.end(err);
        })
});

This function loads the JSON parameters to a variable, initializes an authentication manager, and uses the IdcsAuthenticationManager.getAuthorizationCodeUrl() function of the Node.js SDK to generate the authorization code URL. This function uses promise to either redirect the user's web browser when the authorization code URL is generated or to render an error in the browser.

The following parameters are used to generate the authorization code URL:

Name Description
auth.oracle.redirectURL After a user signs in, Oracle Identity Cloud Service redirects the user’s web browser to this URL. This URL must match the one you’ll configure for the trusted application in the Identity Cloud Service console. See Register the Node.js Application for more information about specifying a redirect URL for the Node.js web application.
auth.oracle.scope The OAuth or OpenID Connect scope of authentication. This application requires only openid authentication.
state The OAuth protocol defines this parameter. The sample Node.js web application uses this code to check whether communication can be established to Oracle Identity Cloud Service. For this example, the value for this parameter is 1234.
response_type The parameter required by the authorization code grant type. For this example, the value for this parameter is code.

After the user signs in, Oracle Identity Cloud Service redirects the user’s web browser to a callback URL, which the developer must implement. The Node.js web application uses the /callback route to handle this request.

//Route for /callback
app.get("/callback", function(req,res){
    //Authentication Manager loaded with the configurations.
    var am = new IdcsAuthenticationManager(auth.oracle);
    //Getting the authorization code from the "code" parameter
    var authZcode = req.query.code;
    //Using the Authentication Manager to exchange the Authorization Code to an Access Token.
    am.authorizationCode(authZcode)
        .then(function(result){
            //Getting the Access and Id Token Values to set in the session.
            req.session.access_token = result.access_token;
            req.session.id_token = result.id_token;
            res.cookie(config.IDCS_COOKIE_NAME, result.access_token);
            res.header('idcs_user_assertion', result.access_token)
            res.redirect('/auth.html');
        }).catch(function(err){
            res.end(err);
        })
});

The Node.js application uses the authorization code to request an access token. The access token is stored as a cookie, which is then sent to the web browser for future use.

The IdcsAuthenticationManager.authorizationCode() function of the Node.js SDK also uses promise (a then-catch statement) to set the access token as a cookie, and to redirect the browser to the /auth.html page.

The Node.js SDK is based on the Node.js passport framework. Therefore, the browser have to forward the access token as a header variable to the /auth URL handler, and use the passport.authenticate() method with the Oracle Identity Cloud Service strategy name as a parameter:

//Uses passport to create a User Session in Node.js.
//Passport sets a user attribute in the request as a json object.
app.get('/auth', passport.authenticate(config.IDCS_STRATEGY_NAME, {}), function(req, res) {
   res.redirect('/home');
});

After the passport.authenticate() method creates the application's session, the function redirects the user’s web browser to a protected URL in the /home application. In addition to /home, the Node.js web application has another protected URL: /myProfile.

Any protected URL needs to check whether the user's session was created previously. The following function is used by each app.get() function for these URLs.

function ensureAuthenticated(req, res, next) {
   if (req.isAuthenticated()) {
      return next();
   }
   res.redirect('/login')
}

The Node.js application handles the /myProfile route and gets information set in the session, as follows:

app.get("/myProfile", ensureAuthenticated, function(req,res){
   //User Manager loaded with the configurations
   var am = new IdcsAuthenticationManager(auth.oracle);
   //Validating id token to acquire information such as UserID, DisplayName, list of groups and AppRoles assigned to the user.
   am.validateIdToken(req.session['id_token'])
    .then(function(idToken){
      res.render('myProfile', {
         layout: 'privateLayout',
         title: 'My Profile',
         user: req.user,
         userInfo: JSON.stringify(idToken, null, 2)
         });
    }).catch(function(err1){
       res.end(err1);
   })
});

After initializing the IdcsAuthenticationManager object, the /myProfile route's handler uses the SDK’s IdcsAuthenticationManager.validateIdToken() function to acquire user information such as display name, user id, and the list of groups and application roles assigned to the user. The JSON object is then parserd as string to the myProfile.handlebars file for rendering in the web browser.

To sign the user out from single sign-on between the application and Oracle Identity Cloud Service, the Node.js web application implements the /logout route, as follows:

app.get('/logout', function(req, res){
  var id_token = req.session.id_token;
  var logouturl = auth.oracle.AudienceServiceUrl + auth.oracle.logoutSufix + '?post_logout_redirect_uri=http%3A//localhost%3A3000&id_token_hint='+ id_token;
  req.session.destroy(function(err) {
    if(err) {
      console.log(err);
    } else {
      req.logout();
      res.clearCookie();
      res.redirect(logouturl);
    }
  })
});

This route invalidates the application’s session, removes any object and cookie set previously, and then redirects the user’s web browser to Oracle Identity Cloud Service's OAuth log out URL.