|
const jwtLib = require('jsonwebtoken'); |
|
const jwksClient = require('jwks-rsa'); |
|
const util = require('util'); // node-js util |
|
var httpRequestPromise = require('request-promise'); |
|
|
|
module.exports.handler = async (event, context) => { |
|
try { |
|
const jwtToken = getToken(event); |
|
const jwtDecoded = jwtLib.decode(jwtToken, { complete: true }); |
|
const myAppUserId = jwtDecoded.payload.userId; |
|
|
|
if (!decoded || !decoded.header || !decoded.header.kid) { |
|
throw new Error('invalid token'); |
|
} |
|
|
|
const client = jwksClient({ |
|
cache: true, |
|
rateLimit: true, |
|
jwksRequestsPerMinute: 10, // Default value |
|
jwksUri: process.env.JWKS_URI |
|
}); |
|
|
|
const jwtKey = await util.promisify(client.getSigningKey); |
|
|
|
const jwtOptions = {audience: process.env.AUDIENCE, issuer: process.env.TOKEN_ISSUER}; |
|
const signingKey = jwtKey.publicKey || jwtKey.rsaPublicKey; |
|
await jwt.verify(token, signingKey, jwtOptions); |
|
|
|
const userData = await httpRequestPromise({ |
|
uri: `http://www.myapp.com/api/users/${myAppUserId}`, |
|
json: true, |
|
}); |
|
|
|
if (!userIsAuthorized(userData)) { |
|
throw new Error('User is not authorized by specific business rules'); |
|
} |
|
|
|
return buildPolicy(event, decoded, userData); |
|
} catch (err) { |
|
console.log(err); |
|
context.fail("Unauthorized"); |
|
return `Unauthorized: ${err.message}`; |
|
} |
|
}; |
|
|
|
function getToken(event) { |
|
if (!event.type || event.type !== 'TOKEN') { |
|
throw new Error('Expected "event.type" parameter to have value "TOKEN"'); |
|
} |
|
|
|
const tokenString = event.authorizationToken; |
|
if (!tokenString) { |
|
throw new Error('Expected "event.authorizationToken" parameter to be set'); |
|
} |
|
|
|
const match = tokenString.match(/^Bearer (.*)$/); |
|
if (!match || match.length < 2) { |
|
throw new Error(`Invalid Authorization token - ${tokenString} does not match "Bearer .*"`); |
|
} |
|
return match[1]; |
|
} |
|
|
|
function userIsAuthorized(userData) { |
|
// Here is where you implement your specifics business rules |
|
return true; |
|
} |
|
|
|
function buildPolicy(decoded, userData) { |
|
return { |
|
principalId: userId, |
|
policyDocument: { |
|
Version: '2012-10-17', // default version |
|
Statement: [{ |
|
Action: 'execute-api:Invoke', // default action |
|
Effect: 'Allow', |
|
Resource: "*" |
|
}] |
|
}, |
|
// the context variable will be sent to the microservice |
|
context: { |
|
scope: decoded.scope, |
|
payload: JSON.stringify(decoded), |
|
userData: JSON.stringify(userData), |
|
userId: userData.id |
|
} |
|
}; |
|
} |