Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@aoberoi/passport-slack

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@aoberoi/passport-slack - npm Package Compare versions

Comparing version 1.0.5 to 2.0.0-beta.1

dist/strategy.d.ts

413

dist/strategy.js

@@ -1,86 +0,10 @@

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
require('babel-polyfill');
var _passportOauth = require('passport-oauth2');
var _passportOauth2 = _interopRequireDefault(_passportOauth);
var _lodash = require('lodash.defaults');
var _lodash2 = _interopRequireDefault(_lodash);
var _lodash3 = require('lodash.pickby');
var _lodash4 = _interopRequireDefault(_lodash3);
var _lodash5 = require('lodash.isfunction');
var _lodash6 = _interopRequireDefault(_lodash5);
var _needle = require('needle');
var _needle2 = _interopRequireDefault(_needle);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const passport_oauth2_1 = __importDefault(require("passport-oauth2")); // tslint:disable-line:import-name
const needle_1 = __importDefault(require("needle"));
const object_entries_1 = __importDefault(require("object.entries"));
/**
* Verify Wrapper
*
* Adapts the verify callback that the super class expects to the verify callback API this
* strategy presents to the user.
* @private
* @param {Object} slackAuthOptions
* @param {boolean} slackAuthOptions.passReqToCallback
* @param {SlackStrategy~verifyCallback} slackAuthOptions.verify
* @return {function} oauth2VerifyCallbackWithRequest
*/
function wrapVerify(slackAuthOptions) {
return function _verify(req, accessToken, refreshToken, params, profile, verified) {
var team = {
id: params.team_id || params.team && params.team.id
};
var teamName = params.team_name || params.team && params.team.name;
if (teamName) team.name = teamName;
var scopes = new Set(params.scope.split(','));
var extra = {};
if (params.bot) {
extra.bot = {
id: params.bot.bot_user_id,
accessToken: params.bot.bot_access_token
};
}
if (params.incoming_webhook) {
extra.incomingWebhook = {
url: params.incoming_webhook.url,
channel: {
name: params.incoming_webhook.channel
},
configurationUrl: params.incoming_webhook.configuration_url
};
if (params.incoming_webhook.channel_id) {
extra.incomingWebhook.channel.id = params.incoming_webhook.channel_id;
}
}
if (!slackAuthOptions.passReqToCallback) {
slackAuthOptions.verify(accessToken, scopes, team, extra, profile, verified);
} else {
slackAuthOptions.verify(req, accessToken, scopes, team, extra, profile, verified);
}
};
}
/**
* Slack Authentication Passport Strategy

@@ -91,198 +15,139 @@ *

*/
var SlackStrategy = function (_OAuth2Strategy) {
_inherits(SlackStrategy, _OAuth2Strategy);
/**
* Creates an instance of the SlackStrategy
* @param {Object} options
* @param {string} options.clientID - Your Slack App's client ID.
* @param {string} options.clientSecret - Your Slack App's client secret.
* @param {string} [options.callbackURL] - The default URL for your webserver to handle
* authorization grants. You will typically use the `passport.authorize('slack')` middleware to
* implement this route, which handles exchanging the authorization grant for an access token.
* This can be overridden using options for `passport.authenticate()` or `passport.authorize()`.
* @param {(string|Array<string>)} [options.scope=identity.basic] - The default scopes used for
* authorization when the `passport.authenticate()` or `passport.authorize()` method options
* don't specify.
* @param {string} [options.team] - The default team for which your application will request
* authorization. This can be overridden using options for `passporrt.authenticate()` or
* `passport.authorize()`.
* @param {boolean} [options.skipUserProfile=false] - Whether or not to retreive a response from
* the `users.identity` Slack API method before invoking the verify callback.
* @param {string} [options.tokenURL=https://slack.com/api/oauth.access]
* @param {string} [options.authorizationURL=https://slack.com/oauth/authorize]
* @param {string} [options.profileURL=https://slack.com/api/users.identity]
* @param {Object} [options.customHeaders={}] - A dictionary of HTTP header names and values to
* be used in all requests made to the Slack API from this Strategy.
* @param {string} [options.name=slack] - The name for this strategy within passport.
* @param {boolean} [options.passReqToCallback=false] - Set to true to give your verify callback
* access to the incoming request.
* @param {string} [options.scopeSeparator=,]
* @param {string} [options.sessionKey] - The key for this strategy to use in a state store.
* @param {Store} [options.store] - **TODO**
* @param {boolean} [options.trustProxy]
* @param {SlackStrategy~verifyCallback} verify - The callback that creates the value to be stored
* in `req.user`, `req.account`, or the customized `options.assignProperty`.
*/
function SlackStrategy(options, verify) {
_classCallCheck(this, SlackStrategy);
if (!options.clientSecret) {
throw new TypeError('SlackStrategy requires a clientSecret option');
}
if (!(0, _lodash6.default)(verify)) {
throw new TypeError('SlackStrategy requires a verify callback');
}
var mergedOptions = (0, _lodash2.default)(options || {}, {
tokenURL: 'https://slack.com/api/oauth.access',
authorizationURL: 'https://slack.com/oauth/authorize',
profileURL: 'https://slack.com/api/users.identity',
passReqToCallback: false,
skipUserProfile: false,
scope: 'identity.basic',
scopeSeparator: ','
});
var slackAuthOptions = {
passReqToCallback: mergedOptions.passReqToCallback,
profileURL: mergedOptions.profileURL,
team: mergedOptions.team,
verify: verify
};
// We saved the user's preference about whether to pass the request to the callback, and now to
// simplify the implementation of wrapVerify, we tell the super class that we always want the
// request passed to the callback.
mergedOptions.passReqToCallback = true;
if (!mergedOptions.skipUserProfile) {
var scopes = mergedOptions.scope;
if (!Array.isArray(mergedOptions.scope)) {
scopes = [mergedOptions.scope];
}
if (!scopes.includes('identity.basic')) {
throw new TypeError('SlackStrategy cannot retrieve user profiles without \'identity.basic\' scope');
}
}
var _this = _possibleConstructorReturn(this, (SlackStrategy.__proto__ || Object.getPrototypeOf(SlackStrategy)).call(this, mergedOptions, wrapVerify(slackAuthOptions)));
_this.name = mergedOptions.name || 'slack';
_this.slackAuthOptions = slackAuthOptions;
return _this;
}
/**
* Retrieve user and team profile from Slack
*
* @param {string} accessToken
* @param {Function} done
*/
_createClass(SlackStrategy, [{
key: 'userProfile',
value: function userProfile(accessToken, done) {
_needle2.default.request('get', this.slackAuthOptions.profileURL, { token: accessToken }, function (error, response, body) {
// TODO: better errors
if (error) {
done(error);
} else if (!body.ok) {
done(new Error(body.error));
} else {
// eslint-disable-next-line no-param-reassign
delete body.ok;
done(null, body);
class SlackStrategy extends passport_oauth2_1.default {
/**
* Creates an instance of the SlackStrategy
*/
constructor(options, verify) {
if (!options.clientSecret) {
throw new TypeError('SlackStrategy requires a clientSecret option');
}
});
// Resolve options by merging in the defaults
const resolvedOptions = Object.assign({
// These are defaults that this strategy provides which the super class does not
tokenURL: 'https://slack.com/api/oauth.access',
authorizationURL: 'https://slack.com/oauth/authorize',
profileURL: 'https://slack.com/api/users.identity',
name: 'slack',
// Apply a default since the wrapVerify behavior depends on resolving this option
passReqToCallback: false,
// Apply a default since warning about a missing scope depends on this option
skipUserProfile: false,
// TODO: we might want to assign a new default value.
// `identity.basic` is the scope needed to fetch the profile info for a user-token app (SIWS), but for Add to
// Slack flows, you wouldn't typically want this scope.
// in workspace apps the equivalent SIWS scope is `identity:read:user`. but again, its very rare that someone
// trying to use the Add to Slack flow would want this scope.
scope: 'identity.basic',
}, options);
// When a user profile is needed, ensure that the scope is set to one of the scopes that can be used for
// `users.identity`, or that its an array that includes one of those scopes.
if (!resolvedOptions.skipUserProfile &&
resolvedOptions.scope !== undefined &&
((typeof resolvedOptions.scope === 'string' &&
!(resolvedOptions.scope === 'identity.basic' || resolvedOptions.scope === 'identity:read:user')) ||
!(resolvedOptions.scope.includes('identity.basic') || resolvedOptions.scope.includes('identity:read:user')))) {
throw new TypeError('SlackStrategy cannot retrieve user profiles without \'identity.basic\' scope');
}
const overrideOptions = { passReqToCallback: true };
super(Object.assign({}, resolvedOptions, overrideOptions), wrapVerify(verify, resolvedOptions.passReqToCallback));
this.slack = {
profileURL: resolvedOptions.profileURL,
team: resolvedOptions.team,
};
}
/**
* Return extra parameters to be included in the authorization request.
*
* @param {Object} options
* @return {Object}
* Retrieve user and team profile from Slack
*/
}, {
key: 'authorizationParams',
value: function authorizationParams(options) {
return (0, _lodash4.default)((0, _lodash2.default)({
team: options.team
}, {
team: this.slackAuthOptions.team
}));
userProfile(accessToken, done) {
needle_1.default.request('get', this.slack.profileURL, { token: accessToken }, (error, _res, body) => {
if (error) {
done(error);
}
else if (!body.ok) {
done(new Error(body.error));
}
else {
done(null, body);
}
});
}
/**
* A callback your application implements to create the value stored on an authenticated request
* as `req.user`, `req.account` (when using the `passport.authorize()` flow), or the customized
* `options.assignProperty` (from instantiaton a {@link SlackStrategy}). You must call the `done`
* function with either an error as the first argument, or the result value as the second
* argument.
*
* @typedef {Function} SlackStrategy~verifyCallback
* @param {http.IncomingMessage} [req] - The HTTP Request. Not present by default. Only exists
* if the `passReqToCallback` option was set when instantiating the strategy.
* @param {string} accessToken - The authenticated user's access token.
* @param {Set<string>} scopes - The set of scopes for which the accessToken is authorized.
* @param {SlackStrategy~Team} team - The Slack Team for which the user has granted your
* application access.
* @param {Object} extra
* @param {?SlackStrategy~BotAuthorization} extra.bot - Details for the authorized Bot User for
* which the user has granted your application in the Slack Team (see scope `bot`).
* @param {?SlackStrategy~IncomingWebhookAuthorization} extra.incomingWebhook - Details for the
* authorized Incoming Webhook for which the user has granted your application in the Slack Team
* (see scope `incoming-webhook`).
* @param {?SlackStrategy~Profile} profile - The User and Team profiles (if they were requested).
* @param {function(?error: Error, ?user: Object): void} done
* Return extra parameters to be included in the authorization request. `state` and `redirect_url` are handled by
* the super class.
*/
/**
* @typedef {Object} SlackStrategy~Team
* @property {string} id
* @property {?string} name - May not always be present, see scope `identity.team`
*/
/**
* @typedef {Object} SlackStrategy~BotAuthorization
* @property {string} userId - The Bot User's user ID.
* @property {string} accessToken - The Bot User's access token.
*/
/**
* @typedef {Object} SlackStrategy~IncomingWebhookAuthorization
* @property {string} url - The URL where your application is authorized by the user to post
* messages.
* @property {string} configurationUrl - The URL where your application can direct a user to
* configure your Incoming WebHook.
* @property {SlackStrategy~Channel} channel - The Channel in the Slack Team where the user has
* authorized your application to post messages.
*/
/**
* @typedef {Object} SlackStrategy~Profile
* @property {Object} user - The representation of the User returned from the `users.identity`
* Web API method. The actual contents depend on the scopes for which your access token is
* authorized. See scopes `identity.basic`, `identity.email`, `identity.avatar`.
* @property {Object} team - The representation of the Team returned from the `users.identity`
* Web API method. The actual contents depends on the scopes for which your access token is
* authorized. See scope `identity.team`.
*/
// TODO: channel.id, is it in there or not? when might it not be?
/**
* @typedef {Object} SlackStrategy~Channel
* @property {string} id
* @property {string} name
*/
/**
* @external {http.IncomingMessage} https://nodejs.org/dist/latest-v6.x/docs/api/http.html#http_class_http_incomingmessage
*/
}]);
return SlackStrategy;
}(_passportOauth2.default);
exports.default = SlackStrategy;
authorizationParams(options) {
const team = options.team || this.slack.team;
if (team !== undefined) {
options.team = team;
}
return options;
}
}
exports.SlackStrategy = SlackStrategy;
/**
* Verify Wrapper
*
* Adapts the verify callback that the super class expects to the verify callback API this strategy presents to the user
*/
function wrapVerify(verify, passReqToCallback) {
return function _verify(req, accessToken, refreshToken, results, // TODO: define some types for the oauth.access response shapes
profile, verified) {
const info = {
access_token: accessToken,
refresh_token: refreshToken,
user: {
// will be undefined for user-token apps that don't fetch the profile
id: results.installer_user ? results.installer_user.user_id : (profile && profile.user && profile.user.id),
name: profile !== undefined && profile.user !== undefined ? profile.user.id : undefined,
},
team: {
id: results.team_id || (results.team && results.team.id),
name: results.team_name || (results.team && results.team.name),
},
scopes: [],
};
// Copy all user profile properties into the user
if (profile !== undefined && profile.user !== undefined) {
for (const [key, val] of object_entries_1.default(profile.user)) {
if (info.user[key] === undefined) {
info.user[key] = val;
}
}
}
// Build scopes info
if (results.current_grant) {
// in workspace apps, a structured object is returned for scopes
info.scopes = results.current_grant.permissions.reduce((scopes, permission) => (scopes.concat(permission.scopes)), info.scopes);
}
else if (results.scope && typeof results.scope === 'string') {
// in all other apps an array is returned, by splitting a string on the comma separator
info.scopes = results.scope.split(',');
}
else {
// TODO: log a warning
}
// TODO: in workspace apps, there's a whole bunch of very important properties that are not
// being passed to the verification callback
// installer_user, authorizing_user, app_id, app_user_id
// Attach info related to bot user
if (results.bot) {
info.bot = {
user_id: results.bot.bot_user_id,
access_token: results.bot.bot_access_token,
};
}
// Attach info related to incoming webhook
if (results.incoming_webhook) {
info.incoming_webhook = results.incoming_webhook;
}
// Invoke the verify callback using the preference for having the req passed or not
if (!passReqToCallback) {
verify(info, verified);
}
else {
verify(req, info, verified);
}
};
}
exports.Strategy = SlackStrategy; // tslint:disable-line:variable-name
//# sourceMappingURL=strategy.js.map
{
"name": "@aoberoi/passport-slack",
"version": "1.0.5",
"version": "2.0.0-beta.1",
"description": "Slack authentication strategy for Passport",
"main": "dist/index.js",
"main": "dist/strategy.js",
"repository": "https://github.com/aoberoi/passport-slack.git",

@@ -10,28 +10,29 @@ "author": "Ankur Oberoi <aoberoi@gmail.com>",

"engines": {
"node": ">=4.2.0"
"node": ">=6"
},
"files": [
"dist/**/*"
],
"scripts": {
"build": "babel src -d dist",
"lint": "tslint --project .",
"build": "npm run build:clean && tsc",
"build:clean": "shx rm -rf ./dist",
"docs": "esdoc -c ./esdoc.json",
"prepare": "npm run build"
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"babel-polyfill": "^6.16.0",
"lodash.defaults": "^4.2.0",
"lodash.isfunction": "^3.0.8",
"lodash.pickby": "^4.6.0",
"needle": "^1.4.2",
"passport-oauth2": "^1.3.0"
"@types/express": "^4.16.0",
"@types/needle": "^2.0.2",
"@types/passport-oauth2": "^1.4.5",
"needle": "^2.2.3",
"object.entries": "^1.0.4",
"passport-oauth2": "^1.4.0"
},
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-es2016": "^6.16.0",
"esdoc": "^0.4.8",
"eslint": "^3.9.0",
"eslint-config-airbnb": "^12.0.0",
"eslint-plugin-import": "^1.16.0",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.8.0"
"esdoc": "^1.1.0",
"shx": "^0.3.2",
"tslint": "^5.11.0",
"tslint-config-airbnb": "^5.11.0",
"typescript": "^3.0.3"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc