Skip to content

Instantly share code, notes, and snippets.

@Colbydude
Created October 23, 2018 16:42
Show Gist options
  • Save Colbydude/dee70ad98490dce6f72727fdda14edd8 to your computer and use it in GitHub Desktop.
Save Colbydude/dee70ad98490dce6f72727fdda14edd8 to your computer and use it in GitHub Desktop.
Quick and dirty AWS Authorizer for Twitch Extensions.
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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment