Skip to main content

Using the Proxy SDK to Authenticate a User

The Proxy SDK creates and manages transactions for when a user needs to perform initial login and subsequent multi-factor authentication(MFA), helping manage state across requests.

When integrating with the Proxy SDK, there are three types of responses which may need to be handled:

  • Allow
  • Deny
  • Require

Note: The Allow response is never returned prior to initial authentication being successful.

These three responses allow for building a workflow like:

  1. User initiates login
    - User may not be able to authenticate at this time. IE Banned country being used to access application
    - User may have to authenticate with a strong factor
  2. User prompted for appropriate login
    - User performs login successfully
  3. Adaptive risk assessment performed
    - User may need to provide further authentication factors
    - User may be allowed to access without MFA due to low evaluated risk score
    - User may be denied access due to high evaluated risk score

Flow state diagram

Depending on the UX required in the application, there are two approaches which can be taken:

  • Have a login page which both performs both collection and initial authentication all at once.
  • Have a page which performs collection and initiates an assessment before the login page is made available
    - You would use this style of page when the pre-authentication rules may render a different experience depending on context
      - e.g. If a login page for fido2 should be used in some situations, or if there are instances where a deny would be returned

This example follows an approach where the policy assessment and invocation of the username/password authentication mechanism occurs within the same request.

// add session awareness
const session = require('express-session')
// add body parsing
const bodyParser = require('body-parser');
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
}))
// Add url form-encoded middleware to process login form
app.use(bodyParser.urlencoded({ extended: true }));

app.post("/login", (req, res) => {
    // Extract parameters from request.
    const username = req.body.username;
    const password = req.body.password;

    var context = {
    sessionId : req.body.sessionId, // The session ID generated posted from the browser
    userAgent : req.headers['user-agent'], // The user-agent collected from headers
    ipAddress : req.ip // The IP address of the connection.
    };

    // Which identity source to use for username/password login.
    // You can discover available identity sources using:
    // https://myidp.ice.ibmcloud.com/developer/explorer/#/Identity_Sources
    const identitySourceId = '6c0e1e52-06f9-4a47-bbd5-089f3498220e';

    // Perform a risk assessment.
    adaptive.assessPolicy(context)
        .then((result) => {
            if (result.status == "deny") {
                    res.status(403).send({ error: "Denied" });
                    return
            }

            // Store the sessionState:
            req.session.transactionId = result.transactionId
            req.session.sessionId = context.sessionId

            if(result.allowedFactors.indexOf("password") != -1) {
                 adaptive.evaluatePassword(context, result.transactionId, identitySourceId, username, password)
                    .then((result) => {
                        if (result.status == "deny") {
                            res.status(403).send({ error: "Denied" });
                            return
                        }
                        if (result.status == "allow") {
                            req.session.token = result.token;
                            res.redirect("/");
                            return
                        }
                      }).catch((error) => {
                        console.log(error);
                        if (error.response.data.messageDescription) {
                          res.status(403).send({ error: error.response.data.messageDescription });
                        } else {
                          res.status(403).send({ error: "Password check failed" });
                        }
                      });
            } else {
                res.status(403).send({ error: "Password login not allowed" });
            }
    });
});

Note: Establish the adaptive object using the initialization steps in Adding the Proxy SDK to an application server


Next: Performing MFA

Previous: Adding the Proxy SDK to an Application Server

See also: Proxy SDK API documentation