twitch-auth
Advanced tools
Comparing version 1.0.3 to 4.2.0-pre.1
{ | ||
"name": "twitch-auth", | ||
"version": "1.0.3", | ||
"description": "Utility module for handling Twitch.tv chatbot authentication.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"version": "4.2.0-pre.1", | ||
"description": "Authenticate with Twitch and stop caring about refreshing tokens.", | ||
"keywords": [ | ||
"twitch", | ||
"auth", | ||
"authentication", | ||
"oauth", | ||
"stream", | ||
"bot" | ||
], | ||
"sideEffects": false, | ||
"main": "lib", | ||
"types": "lib", | ||
"module": "es", | ||
"exports": { | ||
".": { | ||
"require": "./lib/index.js", | ||
"import": "./es/index.mjs" | ||
} | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/laddspencer/twitch-auth.git" | ||
"url": "https://github.com/d-fischer/twitch.git", | ||
"directory": "packages/twitch-auth" | ||
}, | ||
"keywords": [ | ||
"Twitch", | ||
"OAuth" | ||
"homepage": "https://d-fischer.github.io/twitch-auth", | ||
"author": "Daniel Fischer <daniel@d-fischer.dev>", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@d-fischer/shared-utils": "^2.3.1", | ||
"tslib": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"twitch-api-call": "^4.2.0-pre.1" | ||
}, | ||
"peerDependencies": { | ||
"twitch-api-call": "^4.2.0" | ||
}, | ||
"files": [ | ||
"LICENSE", | ||
"README.md", | ||
"lib", | ||
"es" | ||
], | ||
"author": "Ladd Spencer", | ||
"license": "ISC", | ||
"bugs": { | ||
"url": "https://github.com/laddspencer/twitch-auth/issues" | ||
"scripts": { | ||
"build": "tsukuru", | ||
"rebuild": "tsukuru --clean" | ||
}, | ||
"homepage": "https://github.com/laddspencer/twitch-auth#readme", | ||
"dependencies": { | ||
"request": "^2.88.0" | ||
} | ||
"gitHead": "c55950bf6a8c5f8d06c10e3e87d47bb5be0c1ceb" | ||
} |
313
README.md
@@ -1,311 +0,20 @@ | ||
# twitch-auth | ||
Utility module for handling Twitch.tv chatbot authentication. The authentication process is detailed [here](https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#oauth-authorization-code-flow). | ||
# Twitch.js - Authentication | ||
# exports | ||
The following functions are exported by the module. | ||
Authenticate with Twitch and stop caring about refreshing tokens. | ||
## getUserAccessToken(creds, code) | ||
Gets a user access token required for login (using [tmi.js](https://www.npmjs.com/package/tmi.js) for example). | ||
This should be used once after the initial authorization step. Subsequent logins should use the token refresh process. | ||
## Installation | ||
`creds` is an object structured as follows: | ||
``` | ||
{ | ||
"client_id": <your client ID>, | ||
"client_secret": <your client secret> | ||
} | ||
``` | ||
yarn add twitch-auth | ||
`code` is the OAuth 2.0 authorization code returned by Twitch. | ||
or using npm: | ||
Returns a Promise that resolves to an object parsed from the JSON returned from the server, or rejects with an error. The returned object looks like this: | ||
``` | ||
{ | ||
"access_token": "<user access token>", | ||
"refresh_token": "<refresh token>", | ||
"expires_in": <number of seconds until the token expires>, | ||
"scope": "<your previously listed scope(s)>", | ||
"token_type": "bearer" | ||
} | ||
``` | ||
npm install --save twitch-auth | ||
## refreshUserAccessToken(creds, refreshToken) | ||
Gets a new (refreshed) user access token for login. | ||
## Documentation | ||
`creds` ...same as above. | ||
A good place to start with this library is the [documentation](https://d-fischer.github.io/twitch-auth) | ||
which also includes a complete reference of all classes and interfaces, as well as changes and deprecations between major versions. | ||
`refreshToken` is the refresh_token returned from the server in calls to | ||
[getUserAccessToken()](#getuseraccesstokencreds-code) and/or | ||
[refreshUserAccessToken()](#refreshuseraccesstokencreds-refreshtoken). | ||
## If you're getting stuck... | ||
## getAppAccessToken(creds) | ||
Gets an app access token. This is not applicable to chat login, but I wrote the function before I realized that :P | ||
`creds` ...same as above. | ||
# example code | ||
This is basically what I use to launch my chat bot. | ||
It is derived from Twitch's echo/haiku sample and has been built up from there (with the twitch-auth module being refactored out of it). | ||
It uses a local Redis server to cache access/refresh tokens. Run it initially with `-c <auth code>` to get your first user access token. | ||
After that, it will automatically refresh tokens as necessary. | ||
``` | ||
#!/usr/bin/nodejs --harmony | ||
//---------------------------------------------------------------- | ||
'use strict'; | ||
//---------------------------------------------------------------- | ||
const process = require('process') | ||
const minimist = require('minimist') | ||
const fs = require('fs') | ||
const tmi = require('tmi.js') | ||
const redis = require('redis'); | ||
const util = require('util') | ||
// Twitch Auth Util (tau) | ||
const tau = require('twitch-auth') | ||
const defaultConfigPath = 'config.json'; | ||
const defaultConfig = { | ||
credsPath: './creds.json', | ||
reconnect: true | ||
}; | ||
//---------------------------------------------------------------- | ||
// Called every time a message comes in: | ||
function onMessageHandler(target, context, msg, self) { | ||
// Ignore messages from the bot | ||
if (self) { | ||
return; | ||
} | ||
console.log(msg); | ||
} | ||
function parseArgs(argv) { | ||
let args = minimist(argv.slice(2)); | ||
if (args['_'].length > 0) { | ||
args._.forEach((unknownOption) => { | ||
console.log(`I don't know what "${unknownOption}" is.`); | ||
}); | ||
return (null); | ||
} | ||
return (args); | ||
} | ||
function getConfigPath(args, defaultPath=defaultConfigPath) { | ||
if ('F' in args) { | ||
return (args['F']); | ||
} | ||
return (defaultPath); | ||
} | ||
function getConfig(args) { | ||
let configPath = getConfigPath(args); | ||
let config = defaultConfig; | ||
try { | ||
fs.accessSync(configPath, fs.constants.F_OK | fs.constants.R_OK); | ||
let configString = fs.readFileSync(configPath, 'utf8'); | ||
config = Object.assign(config, JSON.parse(configString)); | ||
} | ||
catch (err) { | ||
console.log(err); | ||
} | ||
return (config); | ||
} | ||
function getCreds(credsPath) { | ||
let credString = fs.readFileSync(credsPath, 'utf8'); | ||
return (JSON.parse(credString)); | ||
} | ||
function redisValue(redisClient, key) { | ||
return (new Promise((resolve, reject) => { | ||
redisClient.get(key, (err, result) => { | ||
console.log('redis client returned: ' + result); | ||
if (err) { | ||
reject(err); | ||
} | ||
resolve(result); | ||
}); | ||
})); | ||
} | ||
function accessTokenFromAuthCode(creds, code) { | ||
return (tau.getUserAccessToken(creds, code)); | ||
} | ||
function accessTokenFromCache() { | ||
//console.log('accessTokenFromCache()'); | ||
let redisClient = redis.createClient(); | ||
let tokens = Promise.all([ | ||
redisValue(redisClient, "access_token"), | ||
redisValue(redisClient, "refresh_token")]) | ||
.then((results) => { | ||
//console.log('results: ' + results); | ||
redisClient.end(); | ||
return ({access_token: results[0], | ||
refresh_token: results[1]}); | ||
}); | ||
return (tokens); | ||
} | ||
function cacheTokenResponse(response) { | ||
let redisClient = redis.createClient(); | ||
return (new Promise((resolve, reject) => { | ||
if (('access_token' in response ) && | ||
('refresh_token' in response)) { | ||
redisClient.mset('access_token', response.access_token, | ||
'refresh_token', response.refresh_token, (err, reply) => { | ||
console.log('redis client returned: ' + reply); | ||
redisClient.end(); | ||
if (err) { | ||
reject(err); | ||
} | ||
resolve(reply); | ||
}); | ||
} | ||
})); | ||
} | ||
function reconnect(context) { | ||
return (tau.refreshUserAccessToken(context.creds, context.tokens.refresh_token) | ||
.then((response) => { | ||
// Update the tokens in our context oject. | ||
context.tokens.access_token = response.access_token; | ||
context.tokens.refresh_token = response.refresh_token; | ||
return (response);}) | ||
.then(cacheTokenResponse) | ||
.then((reply) => { | ||
// reply is useless ("OK") | ||
console.log("let's try to reconnect..."); | ||
return (context);}) | ||
.then(serve)); | ||
} | ||
function getTwitchOptions(context) { | ||
let opts = { | ||
options: { | ||
clientId: context.creds.client_id, | ||
debug: true | ||
}, | ||
identity: { | ||
username: context.config.tmi.username, | ||
password: 'oauth:' + context.tokens.access_token | ||
}, | ||
channels: context.config.tmi.channels | ||
} | ||
return (opts); | ||
} | ||
function registerTwitchEventHandlers(client, context) { | ||
// Register our event handlers: | ||
client.on('message', onMessageHandler); | ||
client.on('disconnected', (reason) => { | ||
// Login authentication failed | ||
console.log(util.format('Disconnected: %s', reason)); | ||
reconnect(context) | ||
.catch((err) => { | ||
console.log(err); | ||
}); | ||
}); | ||
} | ||
function serve(context) { | ||
// Create a client with our tmi options: | ||
let opts = getTwitchOptions(context); | ||
let client = new tmi.client(opts); | ||
// Connect to Twitch: | ||
return (client.connect() | ||
.then((data) => { | ||
console.log(JSON.stringify(data)); | ||
registerTwitchEventHandlers(client, context); | ||
}, (err) => { | ||
// Reconnect is almost always necessary because auth tokens need to be refreshed often. | ||
console.log("It's okay, we probably just need to refresh the auth tokens."); | ||
reconnect(context) | ||
.catch((err) => { | ||
console.log('Uh oh, reconnection attempt failed. Maybe this error message will be helpful:\n' + err); | ||
}); | ||
})); | ||
} | ||
function launch(args) { | ||
let config = getConfig(args); | ||
let creds = getCreds(config.credsPath); | ||
let accessToken = Promise.resolve(); | ||
if ('c' in args) { | ||
let authCode = args['c']; | ||
accessToken = accessToken | ||
.then(function() { | ||
return (accessTokenFromAuthCode(creds, authCode)); | ||
}) | ||
.then((response) => { | ||
return (cacheTokenResponse(response)); | ||
}); | ||
} | ||
else { | ||
accessToken = accessToken | ||
.then(function() { | ||
return (accessTokenFromCache()); | ||
}); | ||
} | ||
// Inject other context. | ||
accessToken | ||
.then((tokens) => { | ||
let context = { | ||
config: config, | ||
creds: creds, | ||
tokens: tokens | ||
}; | ||
return (context);}) | ||
.then(serve) | ||
.catch((err) => { | ||
console.log(err); | ||
process.exit(1); | ||
}); | ||
} | ||
//---------------------------------------------------------------- | ||
launch(parseArgs(process.argv)); | ||
//---------------------------------------------------------------- | ||
``` | ||
My `config.json` looks like this: | ||
``` | ||
{ | ||
"tmi": { | ||
"channels": [ | ||
"laddspencer" | ||
], | ||
"username": "PhantsBot" | ||
} | ||
} | ||
``` | ||
My `creds.json` looks like this (no, those are not real creds, use your own!): | ||
``` | ||
{ | ||
"client_id": "4jkcd8ejjwkemvnhuewnc98ku87uyh", | ||
"client_secret": "d9rkkijun4jfunywhqssx6456hey7u" | ||
} | ||
``` | ||
You can join the [Discord server](https://discord.gg/b9ZqMfz) for support. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
89562
36
2099
3
1
1
21
2
+ Addedtslib@^2.0.0
+ Added@d-fischer/cross-fetch@4.2.1(transitive)
+ Added@d-fischer/logger@3.1.0(transitive)
+ Added@d-fischer/qs@7.0.2(transitive)
+ Added@d-fischer/shared-utils@2.4.23.6.3(transitive)
+ Added@types/node@14.18.63(transitive)
+ Added@types/node-fetch@2.6.11(transitive)
+ Addeddetect-node@2.1.0(transitive)
+ Addedform-data@4.0.1(transitive)
+ Addednode-fetch@2.7.0(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedtslib@2.8.1(transitive)
+ Addedtwitch-api-call@4.6.7(transitive)
+ Addedtwitch-common@4.6.7(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)
- Removedrequest@^2.88.0
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removeddashdash@1.14.1(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpsl@1.10.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)