3

We have a front end react app that has MSAL login that uses aws api gateway api endpoints for backend operations. After the login process I would like to send the bearer Token to the api and get it authenticated. From what I have read online you do this by using node.js and passport.authenticate(). Problem is trying to make this work in aws api gateway. So I came up with a scheme to do the authentication through a Authorizer lambda. 1) Use aws-serverless-express to run express as api proxy in lambda 2) Use passport-azure-ad module to set bearerstrategy. 3) run passport.authenticate() to authenticate token. 4) upon valid token return allow policy from lambda 5) The api request will continue on

I just placed the following files and required node modules into a node.js lambda. So this essentially is a middlewear between client and api. If token is valid will allow request to go through.

During my tests I am getting this error when it applies the bearerstrategy:

{ "name": "AzureAD: Bearer Strategy", "hostname": "169.254.43.173", "pid": 8, "level": 30, "msg": "authentication failed due to: token is not found", "time": "2020-08-24T23:48:35.497Z", "v": 0 }

Would be great if there is a simpler way to authenticate a Bearer token.

Lambda index.js file:

const awsServerlessExpress = require('aws-serverless-express')
const app = require('./app')
const server = awsServerlessExpress.createServer(app)

exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context)

config.js

'use strict';

const config = {
    identityMetadata: "https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration",
    clientID: "xxxxxxxxxxxxxxxxxxxx",
    validateIssuer: true,
    loggingLevel: 'info',
    passReqToCallback: false,
    ignoreExpiration: true
};

module.exports = config

app.js file

'use strict'
const express = require('express')
const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')
const passport = require("passport");
const config = require('./config');
const BearerStrategy = require('passport-azure-ad').BearerStrategy;
const bearerStrategy = new BearerStrategy(config, (token, done) => {
    // Send user info using the second argument
    done(null, {}, token);
}
);
const app = express();
app.use(passport.initialize());
const router = express.Router()
passport.use(bearerStrategy);

router.use(awsServerlessExpressMiddleware.eventContext())

var generatePolicy = function(effect, resource) {
    var authResponse = {};
    authResponse.principalId = 'user';
    if (effect && resource) {
        var policyDocument = {};
        policyDocument.Version = '2012-10-17'; // default version
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; // default action
        statementOne.Effect = effect;
        statementOne.Resource = "*";
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }
    return authResponse;
}
        
var generateAllow = function(resource) {
    return generatePolicy('Allow', resource);
}

router.get('/', passport.authenticate('oauth-bearer', {session: false}),
    (req, res) => {
        res.send(generateAllow(req.apiGateway.event.methodArn))        
    }
);

// The aws-serverless-express library creates a server and listens on a Unix
// Domain Socket for you, so you can remove the usual call to app.listen.
// app.listen(3000)
app.use('/', router)

// Export your express server so you can import it in the lambda function.
module.exports = app
Andy N
  • 1,013
  • 9
  • 25

0 Answers0