function ValidateToken()

in src/authorizer/index.js [60:198]


function ValidateToken(pems, event, context, callback) {

    var token = event.authorizationToken;

    // the auth header may come in the format of "Bearer <token>" or "<token>"
    var parts = token.split(' ');
    if (parts.length == 2) {
        var schema = parts.shift().toLowerCase();
        token = parts.join(' ');
        if ('bearer' != schema) {
            console.log("Schema " + schema + " not supported");
            context.fail("Unauthorized");
            return;
        }
    }

    //Fail if the token is not jwt
    var decodedJwt = jwt.decode(token, {complete: true});
    if (!decodedJwt) {
        console.log("Not a valid JWT token");
        context.fail("Unauthorized");
        return;
    }

    //Fail if token is not from your UserPool
    if (decodedJwt.payload.iss != iss) {
        console.log("invalid issuer");
        context.fail("Unauthorized");
        return;
    }

    //Reject the jwt if it's not an 'Access Token'
    if (decodedJwt.payload.token_use != 'access') {
        console.log("Not an access token");
        context.fail("Unauthorized");
        return;
    }

    //Get the kid from the token and retrieve corresponding PEM
    var kid = decodedJwt.header.kid;
    var pem = pems[kid];
    if (!pem) {
        console.log('Invalid access token');
        context.fail("Unauthorized");
        return;
    }

    //Verify the signature of the JWT token to ensure it's really coming from your User Pool

    jwt.verify(token, pem, {issuer: iss}, function (err, payload) {
        if (err) {
            console.log("error verifying token: " + JSON.stringify(err, null, 2));
            context.fail("Unauthorized");
        } else {
            console.log("Token payload: " + JSON.stringify(payload));
            //Valid token. Generate the API Gateway policy for the user
            //Always generate the policy on value of 'sub' claim and not for 'username' because username is reassignable
            //sub is UUID for a user which is never reassigned to another user.
            var principalId = payload.username;

            //Get AWS AccountId and API Options
            var apiOptions = {};
            var tmp = event.methodArn.split(':');
            var apiGatewayArnTmp = tmp[5].split('/');
            var awsAccountId = tmp[4];
            apiOptions.region = tmp[3];
            apiOptions.restApiId = apiGatewayArnTmp[0];
            apiOptions.stage = apiGatewayArnTmp[1];
            var method = apiGatewayArnTmp[2];
            var resource = '/'; // root resource
            if (apiGatewayArnTmp[3]) {
                resource += apiGatewayArnTmp[3];
            }
            //For more information on specifics of generating policy, refer to blueprint for API Gateway's Custom authorizer in Lambda console
            var policy = new AuthPolicy(principalId, awsAccountId, apiOptions);

            // Any authenticated clients can list customization options
            policy.allowMethod(AuthPolicy.HttpVerb.GET, "/horns");
            policy.allowMethod(AuthPolicy.HttpVerb.GET, "/socks");
            policy.allowMethod(AuthPolicy.HttpVerb.GET, "/glasses");
            policy.allowMethod(AuthPolicy.HttpVerb.GET, "/capes");

            // When the scope matches the partner admin scope
            if (payload.scope.includes(PARTNER_ADMIN_SCOPE)) {
                policy.allowMethod(AuthPolicy.HttpVerb.GET, "/partner*");
                policy.allowMethod(AuthPolicy.HttpVerb.POST, "/partner*");
                policy.allowMethod(AuthPolicy.HttpVerb.DELETE, "/partner*");

                const authResponse = policy.build();
                console.log("authResponse:" + JSON.stringify(authResponse, null, 2));
                callback(null, authResponse);
                return;
            }

            // When the scope matches the unicorn customizations scope, ensure the company can be found in the ID loopup table
            if (payload.scope.includes(CUSTOMIZE_SCOPE)) {
                policy.allowMethod(AuthPolicy.HttpVerb.GET, "/customizations*");
                policy.allowMethod(AuthPolicy.HttpVerb.POST, "/customizations*");
                policy.allowMethod(AuthPolicy.HttpVerb.DELETE, "/customizations*");
                const authResponse = policy.build();

                // look up the backend ID for the company
                var params = {
                    TableName: companyDDBTable,
                    Key: {'ClientID': payload["client_id"]}
                };

                ddbDocClient.get(params).promise().then(data => {
                    console.log("DDB response:\n" + JSON.stringify(data));
                    if (data["Item"] && "CompanyID" in data["Item"]) {
                        authResponse.context = {
                            CompanyID: data["Item"]["CompanyID"]
                        };

                        // Uncomment here to pass on the client ID as the api key in the auth response
                        // authResponse.usageIdentifierKey = payload["client_id"];

                        console.log("authResponse:" + JSON.stringify(authResponse, null, 2));
                        callback(null, authResponse);
                        return;
                    } else {
                        console.log("did not find matching clientID");
                        context.fail("Unauthorized");
                        return;
                    }

                }).catch(err => {
                    console.error((err));
                    callback("Error: Internal Error");
                    return;
                });
            } else {
                console.log("did not find matching clientID");
                context.fail("Unauthorized");
                return;
            }
        }
    });
}