Framework fundementals - OCLC-Developer-Network/devconnect2018-idm GitHub Wiki
Configuration
- In project root create file prod_config.yml
- Edit prod_config.yml so it contains a set of key value pairs with:
- wskey key
- wskey secret
- principalID
- principalIDNS
- institution registry ID
 
wskey: test
secret: secret
principalID: id 
principalIDNS: namespace
institution: 128807
Creating the Application Entry point
- Create a file called server.js
- Open server.js
- Load dependencies
"use strict";
const express = require('express');
const bodyParser = require('body-parser');
const nodeauth = require("nodeauth");
const User = require("./user.js")
const UserError = require("./UserError.js")
- Configure the application
- use ejs to render html templates
- set directory where views are stored to views
 
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.set('views', 'views'); 
 
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
module.exports = app;
Create code to load configuration information
- 
In src folder create a file called config.js 
- 
Open config.js - Create a function that loads the configuration data file as a string based on the environment
 "use strict"; const fs = require('fs'); module.exports = function get_config(environment) { let config = fs.readFileSync(require('path').resolve(__dirname, '../' + environment + '_config.yml')).toString(); return config; };
Create local configuration for running application
- In project root create a file called local.js
- Open local.js
- Require yaml parsing library
- Require src/config.js
- Set the environment
- Load the configuration
- Require src/server.js
- Tell application what port to run on
- Log what application is doing
 
const yaml = require('js-yaml');
const get_config = require("./src/config.js");
let environment = 'prod';
global.config = yaml.load(get_config(environment));
let app = require('./src/server.js');
let port = process.env.PORT || 8000;
// Server
app.listen(port, () => {
    console.log(`Listening on: http://localhost:${port}`);
});
        
Add script for starting app to package.json
- Open package.json
- In scripts section add
"start": "nodemon local.js",
Application Authentication
Authentication happens repeatedly in our application so we want to create a reusable function to handle Authentication when we need it. To do this we're using something called a "Middleware". The idea behind middleware is to allow us to intercept any request and tell the application to do something before and/or application request. In this case we're the application that anytime this function is called it should perform authentication BEFORE the client request.
- Open server.js
- Add authentication setup
- instantiate wskey object with appropriate "options"
 
const options = {
        services: ["SCIM:read_self", "refresh_token"],
        redirectUri: "http://localhost:8000/loggedIn"
    };
const wskey = new nodeauth.Wskey(config['wskey'], config['secret'], options);
- Create a function that retrieve an Access token
- Check for an error code in the query paramters
- if present, render the error page template
 
- Check for an existing valid Access Token
- if present go on your way
 
- Check for valid Refresh Token
- if present, use it to get a valid Access Token
 
- Check for Authorization code
- if present, use it to get a valid Access Token
 - if request succeed, set the Access token as an app variable and go on your way
- if request fails, render error page template
 
- If none of the above, redirect the user login
 
- Check for an error code in the query paramters
    if (req.query['error']){
        res.render('display-error', {error: req.query['error'], error_message: req.query['error_description'], error_detail: ""});
    } else if (app.get('accessToken') && app.get('accessToken').getAccessTokenString() && !app.get('accessToken').isExpired()){
        next()
    } else if (app.get('accessToken') && !app.get('accessToken').refreshToken.isExpired()) {    
        app.get('accessToken').refresh();
        next();
    } else if (req.query['code']) { 
        // request an Access Token
        wskey.getAccessTokenWithAuthCode(req.query['code'], config['institution'], config['institution'])
            .then(function (accessToken) {
                app.set('accessToken', accessToken);
                //redirect to the state parameter
                let state = decodeURIComponent(req.query['state']);
                res.redirect(state);
            })
            .catch(function (err) {
                //catch the error
                let error = new UserError(err);
                res.render('display-error', {error: error.getCode(), error_message: error.getMessage(), error_detail: error.getDetail()});
            })
    }else { 
        // redirect to login + state parameter
        res.redirect(wskey.getLoginURL(config['institution'], config['institution']) + "&state=" + encodeURIComponent(req.originalUrl));
    }  
- Add application level middleware which performs authentication everywhere using getAccessToken function.
app.use(function (req, res, next) {
    getAccessToken(req, res, next);
});