|
const jwt = require('jsonwebtoken'); |
|
|
|
// Create a Secrets Manager client |
|
const SecretManager = new AWS.SecretsManager({ |
|
endpoint: "<SECRET MANAGER ENDPOINT HERE>", |
|
region: "<REGION>" |
|
}); |
|
|
|
/** |
|
* Authorizer to validate JWTs signed by Twitch. |
|
*/ |
|
exports.authorizer = (event, context, callback) => { |
|
let bearerJwt = /^Bearer ([A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+)$/ |
|
.exec(event.authorizationToken); |
|
|
|
if (!bearerJwt) { |
|
return callback('Unauthorized'); |
|
} |
|
|
|
bearerJwt = bearerJwt[1]; |
|
|
|
fetchSecret() |
|
.then(verifyJwt.bind(null, bearerJwt)) |
|
.catch(error => { |
|
// console.log(error); |
|
callback('Unauthorized'); |
|
}) |
|
.then(generatePolicy) |
|
.then(policy => callback(null, policy)) |
|
.catch(error => { |
|
// console.log(error); |
|
callback(error); |
|
}); |
|
}; |
|
|
|
/** |
|
* Fetches the secret from AWS Secrets Manager. |
|
*/ |
|
function fetchSecret () { |
|
// Get the secret value. |
|
return SecretManager |
|
.getSecretValue({SecretId: '<SECRET ID HERE>'}).promise(); |
|
} |
|
|
|
/** |
|
* Generate an AWS Policy to define which API methods the given token is authorized to invoke. |
|
*/ |
|
function generatePolicy (jwt) { |
|
let policy = { |
|
principalId: 'user', |
|
policyDocument: { |
|
Version: '2012-10-17', |
|
Statement: [{ |
|
Action: 'execute-api:Invoke', |
|
Effect: 'Allow', |
|
Resource: [ |
|
// All resources a viewer can access here. |
|
] |
|
}] |
|
}, |
|
context: { |
|
opaqueUserId: jwt.opaque_user_id, // Opaque User ID for the person making the request. |
|
channelId: jwt.channel_id, // Channel ID the request is coming from. |
|
role: jwt.role // Type of user the JWT has been signed for. |
|
// @NOTE More about the Twitch JWT Schema here: https://dev.twitch.tv/docs/extensions/reference/#jwt-schema |
|
} |
|
}; |
|
|
|
if (jwt.role == 'broadcaster') { |
|
policy.policyDocument.Statement[0].Resource.push( |
|
// All resources a broadcaster can access here. |
|
); |
|
} |
|
|
|
if (jwt.user_id) { |
|
// The user's Twitch user ID. This will only be here if the user grants permission |
|
// for the extension to identify them. Which is where Opaque User IDs come into play. |
|
policy.context.userId = jwt.user_id; |
|
} |
|
|
|
return policy; |
|
} |
|
|
|
/** |
|
* Verifies the JWT is properly signed. |
|
*/ |
|
function verifyJwt (token, data) { |
|
let secret = JSON.parse(data.SecretString).jwt_secret; |
|
secret = new Buffer(secret, 'base64'); |
|
|
|
const options = { algorithms: ['HS256'] }; |
|
|
|
return jwt.verify(token, secret, options); |
|
} |