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

@slack/oauth

Package Overview
Dependencies
Maintainers
15
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@slack/oauth - npm Package Compare versions

Comparing version 1.2.0 to 1.3.0-orgAppsBeta.4

48

dist/index.d.ts

@@ -28,6 +28,10 @@ /// <reference types="node" />

/**
* Fetches data from the installationStore.
* Fetches data from the installationStore for non Org Installations.
*/
authorize(source: InstallationQuery): Promise<AuthorizeResult>;
/**
* Fetches data from the installationStore for Org Installations.
*/
orgAuthorize(source: OrgInstallationQuery): Promise<AuthorizeResult>;
/**
* Returns a URL that is suitable for including in an Add to Slack button

@@ -54,3 +58,3 @@ * Uses stateStore to generate a value for the state query param.

installationStore?: InstallationStore;
authVersion: 'v1' | 'v2';
authVersion?: 'v1' | 'v2';
logger?: Logger;

@@ -69,3 +73,3 @@ logLevel?: LogLevel;

export interface CallbackOptions {
success?: (installation: Installation, options: InstallURLOptions, callbackReq: IncomingMessage, callbackRes: ServerResponse) => void;
success?: (installation: Installation | OrgInstallation, options: InstallURLOptions, callbackReq: IncomingMessage, callbackRes: ServerResponse) => void;
failure?: (error: CodedError, options: InstallURLOptions, callbackReq: IncomingMessage, callbackRes: ServerResponse) => void;

@@ -79,3 +83,5 @@ }

storeInstallation: (installation: Installation, logger?: Logger) => Promise<void>;
storeOrgInstallation?: (installation: OrgInstallation, logger?: Logger) => Promise<void>;
fetchInstallation: (query: InstallationQuery, logger?: Logger) => Promise<Installation>;
fetchOrgInstallation?: (query: OrgInstallationQuery, logger?: Logger) => Promise<OrgInstallation>;
}

@@ -110,3 +116,32 @@ export interface Installation {

tokenType?: string;
isEnterpriseInstall?: boolean;
orgDashboardGrantAccess?: string;
}
export interface OrgInstallation {
enterprise: {
id: string;
name?: string;
};
bot?: {
token: string;
scopes: string[];
id?: string;
userId: string;
};
user: {
token?: string;
scopes?: string[];
id: string;
};
incomingWebhook?: {
url: string;
channel: string;
channelId: string;
configurationUrl: string;
};
appId: string | undefined;
tokenType?: string;
isEnterpriseInstall: boolean;
orgDashboardGrantAccess?: string;
}
export interface InstallationQuery {

@@ -118,2 +153,8 @@ teamId: string;

}
export interface OrgInstallationQuery {
enterpriseId: string;
teamId?: string;
userId?: string;
conversationId?: string;
}
export interface AuthorizeResult {

@@ -124,4 +165,5 @@ botToken?: string;

botUserId?: string;
teamId?: string;
}
export { Logger, LogLevel } from './logger';
//# sourceMappingURL=index.d.ts.map

212

dist/index.js

@@ -97,2 +97,3 @@ "use strict";

this.authorize = this.authorize.bind(this);
this.orgAuthorize = this.orgAuthorize.bind(this);
this.authVersion = authVersion;

@@ -109,3 +110,3 @@ this.authorizationUrl = authorizationUrl;

/**
* Fetches data from the installationStore.
* Fetches data from the installationStore for non Org Installations.
*/

@@ -127,2 +128,3 @@ InstallProvider.prototype.authorize = function (source) {

authResult.userToken = queryResult.user.token;
authResult.teamId = queryResult.team.id;
if (queryResult.bot !== undefined) {

@@ -143,2 +145,37 @@ authResult.botToken = queryResult.bot.token;

/**
* Fetches data from the installationStore for Org Installations.
*/
InstallProvider.prototype.orgAuthorize = function (source) {
return __awaiter(this, void 0, void 0, function () {
var queryResult, authResult, error_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
if (this.installationStore.fetchOrgInstallation === undefined) {
throw new Error('Installation Store is missing the fetchOrgInstallation method');
}
return [4 /*yield*/, this.installationStore.fetchOrgInstallation(source, this.logger)];
case 1:
queryResult = _a.sent();
if (queryResult === undefined) {
throw new Error('Failed fetching data from the Installation Store');
}
authResult = {};
authResult.userToken = queryResult.user.token;
if (queryResult.bot !== undefined) {
authResult.botToken = queryResult.bot.token;
authResult.botId = queryResult.bot.id;
authResult.botUserId = queryResult.bot.userId;
}
return [2 /*return*/, authResult];
case 2:
error_2 = _a.sent();
throw new errors_1.AuthorizationError(error_2.message);
case 3: return [2 /*return*/];
}
});
});
};
/**
* Returns a URL that is suitable for including in an Add to Slack button

@@ -206,7 +243,7 @@ * Uses stateStore to generate a value for the state query param.

return __awaiter(this, void 0, void 0, function () {
var parsedUrl, code, state, installOptions, client, resp, installation, botId, botId, error_2;
var parsedUrl, code, state, installOptions, client, resp, installation, authResult, botId, authResult, botId, orgDashboardGrantAccess, error_3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 10, , 11]);
_a.trys.push([0, 13, , 14]);
if (req.url !== undefined) {

@@ -246,9 +283,10 @@ parsedUrl = url_1.parse(req.url, true);

scopes: resp.scope.split(','),
id: '',
id: resp.user_id !== undefined ? resp.user_id : '',
},
};
if (!(resp.bot !== undefined)) return [3 /*break*/, 4];
return [4 /*yield*/, getBotId(resp.bot.bot_access_token, this.clientOptions)];
return [4 /*yield*/, runAuthTest(resp.bot.bot_access_token, this.clientOptions)];
case 3:
botId = _a.sent();
authResult = _a.sent();
botId = authResult.bot_id !== undefined ? authResult.bot_id : '';
installation.bot = {

@@ -277,28 +315,42 @@ id: botId,

resp = (_a.sent());
return [4 /*yield*/, getBotId(resp.access_token, this.clientOptions)];
return [4 /*yield*/, runAuthTest(resp.access_token, this.clientOptions)];
case 7:
botId = _a.sent();
authResult = _a.sent();
botId = authResult.bot_id !== undefined ? authResult.bot_id : '';
orgDashboardGrantAccess = authResult.url !== undefined ? authResult.url : undefined;
// resp obj for v2 - https://api.slack.com/methods/oauth.v2.access#response
installation = {
team: resp.team,
appId: resp.app_id,
user: {
token: resp.authed_user.access_token,
scopes: resp.authed_user.scope !== undefined ? resp.authed_user.scope.split(',') : undefined,
id: resp.authed_user.id,
},
bot: {
scopes: resp.scope.split(','),
token: resp.access_token,
userId: resp.bot_user_id,
id: botId,
},
tokenType: resp.token_type,
};
if (resp.enterprise !== null) {
installation.enterprise = {
id: resp.enterprise.id,
name: resp.enterprise.name,
if (resp.is_enterprise_install) {
// org installation
installation = {
orgDashboardGrantAccess: orgDashboardGrantAccess,
enterprise: resp.enterprise,
appId: resp.app_id,
user: {
token: resp.authed_user.access_token,
scopes: resp.authed_user.scope !== undefined ? resp.authed_user.scope.split(',') : undefined,
id: resp.authed_user.id,
},
bot: {
scopes: resp.scope.split(','),
token: resp.access_token,
userId: resp.bot_user_id,
id: botId,
},
tokenType: resp.token_type,
isEnterpriseInstall: resp.is_enterprise_install,
};
}
else {
// workspace or non org enterprise installation
installation = __assign(__assign(__assign({ team: resp.team }, (resp.enterprise !== null && resp.enterprise !== undefined) ? { enterprise: resp.enterprise } : {}), { appId: resp.app_id, user: {
token: resp.authed_user.access_token,
scopes: resp.authed_user.scope !== undefined ? resp.authed_user.scope.split(',') : undefined,
id: resp.authed_user.id,
}, bot: {
scopes: resp.scope.split(','),
token: resp.access_token,
userId: resp.bot_user_id,
id: botId,
}, tokenType: resp.token_type }), (resp.is_enterprise_install !== undefined) ? { isEnterpriseInstall: resp.is_enterprise_install } : {});
}
_a.label = 8;

@@ -314,7 +366,20 @@ case 8:

}
// save access code to installationStore
return [4 /*yield*/, this.installationStore.storeInstallation(installation, this.logger)];
if (!installation.isEnterpriseInstall) return [3 /*break*/, 10];
if (this.installationStore.storeOrgInstallation === undefined) {
throw new Error('Installation store is missing the storeOrgInstallation method');
}
// save token to orgInstallationStore
return [4 /*yield*/, this.installationStore.storeOrgInstallation(installation, this.logger)];
case 9:
// save access code to installationStore
// save token to orgInstallationStore
_a.sent();
return [3 /*break*/, 12];
case 10:
// save token to InstallationStore
return [4 /*yield*/, this.installationStore.storeInstallation(installation, this.logger)];
case 11:
// save token to InstallationStore
_a.sent();
_a.label = 12;
case 12:
if (options !== undefined && options.success !== undefined) {

@@ -328,16 +393,16 @@ this.logger.debug('calling passed in options.success');

}
return [3 /*break*/, 11];
case 10:
error_2 = _a.sent();
this.logger.error(error_2);
return [3 /*break*/, 14];
case 13:
error_3 = _a.sent();
this.logger.error(error_3);
if (options !== undefined && options.failure !== undefined) {
this.logger.debug('calling passed in options.failure');
options.failure(error_2, installOptions, req, res);
options.failure(error_3, installOptions, req, res);
}
else {
this.logger.debug('run built-in failure function');
callbackFailure(error_2, installOptions, req, res);
callbackFailure(error_3, installOptions, req, res);
}
return [3 /*break*/, 11];
case 11: return [2 /*return*/];
return [3 /*break*/, 14];
case 14: return [2 /*return*/];
}

@@ -388,10 +453,32 @@ });

// db write
this.devDB[installation.team.id] = installation;
return [2 /*return*/];
if (isNotOrgInstall(installation)) {
this.devDB[installation.team.id] = installation;
}
else {
throw new Error('Failed saving installation data to installationStore');
}
return [2 /*return*/, Promise.resolve()];
});
});
};
MemoryInstallationStore.prototype.storeOrgInstallation = function (installation, logger) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (logger !== undefined) {
logger.warn('Storing Access Token. Please use a real Installation Store for production!');
}
// db write
if (installation.isEnterpriseInstall) {
this.devDB[installation.enterprise.id] = installation;
}
else {
throw new Error('Failed saving installation data to installationStore');
}
return [2 /*return*/, Promise.resolve()];
});
});
};
// non org app lookup
MemoryInstallationStore.prototype.fetchInstallation = function (query, logger) {
return __awaiter(this, void 0, void 0, function () {
var item;
return __generator(this, function (_a) {

@@ -401,7 +488,23 @@ if (logger !== undefined) {

}
item = this.devDB[query.teamId];
return [2 /*return*/, item];
if (query.teamId !== undefined) {
return [2 /*return*/, this.devDB[query.teamId]];
}
throw new Error('Failed fetching installation');
});
});
};
// enterprise org app installation lookup
MemoryInstallationStore.prototype.fetchOrgInstallation = function (query, logger) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (logger !== undefined) {
logger.warn('Retrieving Access Token from DB. Please use a real Installation Store for production!');
}
if (query.enterpriseId !== undefined) {
return [2 /*return*/, this.devDB[query.enterpriseId]];
}
throw new Error('Failed fetching installation');
});
});
};
return MemoryInstallationStore;

@@ -412,3 +515,3 @@ }());

var redirectUrl;
if (installation.team !== null && installation.team.id !== undefined && installation.appId !== undefined) {
if (isNotOrgInstall(installation) && installation.appId !== undefined) {
// redirect back to Slack native app

@@ -418,2 +521,8 @@ // Changes to the workspace app was installed to, to the app home

}
else if (installation.isEnterpriseInstall &&
installation.appId !== undefined &&
installation.orgDashboardGrantAccess !== undefined) {
// org app install
redirectUrl = installation.orgDashboardGrantAccess + "manage/organization/apps/profile/" + installation.appId + "/workspaces/add";
}
else {

@@ -434,3 +543,3 @@ // redirect back to Slack native app

// Gets the bot_id using the `auth.test` method.
function getBotId(token, clientOptions) {
function runAuthTest(token, clientOptions) {
return __awaiter(this, void 0, void 0, function () {

@@ -445,8 +554,3 @@ var client, authResult;

authResult = _a.sent();
if (authResult.bot_id !== undefined) {
return [2 /*return*/, authResult.bot_id];
}
// If a user token was used for auth.test, there is no bot_id
// return an empty string in this case
return [2 /*return*/, ''];
return [2 /*return*/, authResult];
}

@@ -456,4 +560,8 @@ });

}
// type guard to confirm an installation isn't an OrgInstallation
function isNotOrgInstall(installation) {
return installation.team !== undefined && installation.team !== null;
}
var logger_2 = require("./logger");
exports.LogLevel = logger_2.LogLevel;
//# sourceMappingURL=index.js.map
{
"name": "@slack/oauth",
"version": "1.2.0",
"version": "1.3.0-orgAppsBeta.4",
"description": "Official library for interacting with Slack's Oauth endpoints",

@@ -5,0 +5,0 @@ "author": "Slack Technologies, Inc.",

@@ -35,3 +35,3 @@ # Slack OAuth

This package exposes an `InstallProvider` class, which sets up the required configuration and exposes methods such as `generateInstallUrl`, `handleCallback`, `authorize` for use within your apps. At a minimum, `InstallProvider` takes a `clientId` and `clientSecret` (both which can be obtained under the **Basic Information** of your app configuration). `InstallProvider` also requires a `stateSecret`, which is used to encode the generated state, and later used to decode that same state to verify it wasn't tampered with during the OAuth flow. **Note**: This example is not ready for production because it only stores installations (tokens) in memory. Please go to the [storing installations in a database](#storing-installations-in-a-database) section to learn how to plug in your own database.
This package exposes an `InstallProvider` class, which sets up the required configuration and exposes methods such as `generateInstallUrl`, `handleCallback`, `authorize`, `orgAuthorize` for use within your apps. At a minimum, `InstallProvider` takes a `clientId` and `clientSecret` (both which can be obtained under the **Basic Information** of your app configuration). `InstallProvider` also requires a `stateSecret`, which is used to encode the generated state, and later used to decode that same state to verify it wasn't tampered with during the OAuth flow. **Note**: This example is not ready for production because it only stores installations (tokens) in memory. Please go to the [storing installations in a database](#storing-installations-in-a-database) section to learn how to plug in your own database.

@@ -166,6 +166,8 @@ ```javascript

An installation store is an object that provides two methods: `storeInstallation` and `fetchInstallation`. `storeInstallation` takes an `installation` as an argument, which is an object that contains all installation related data (like tokens, teamIds, enterpriseIds, etc). `fetchInstallation` takes in a `installQuery`, which is used to query the database. The `installQuery` can contain `teamId`, `enterpriseId`, `userId`, and `conversationId`.
An installation store is an object that provides four methods: `storeInstallation`, `storeOrgInstallation`, `fetchInstallation` and `fetchOrgInstallation`. `storeInstallation` and `storeOrgInstallation` takes an `installation` as an argument, which is an object that contains all installation related data (like tokens, teamIds, enterpriseIds, etc). `fetchInstallation` and `fetchOrgInstallation` takes in a `installQuery`, which is used to query the database. The `installQuery` can contain `teamId`, `enterpriseId`, `userId`, and `conversationId`.
In the following example, the `installationStore` option is used and the object is defined in line. The required methods are implemented by calling an example database library with simple get and set operations.
**Note**: `fetchOrgInstallation` and `storeOrgInstallation` were introduced to support Org wide app installations (currently in beta).
In the following example, the `installationStore` option is used and the object is defined in line. The methods are implemented by calling an example database library with simple get and set operations.
```javascript

@@ -181,4 +183,8 @@ const installer = new InstallProvider({

// replace myDB.set with your own database or OEM setter
myDB.set(installation.team.id, installation);
return;
if (installation.team.id !== undefined) {
// non enterprise org app installation
return myDB.set(installation.team.id, installation);
} else {
throw new Error('Failed saving installation data to installationStore');
}
},

@@ -188,6 +194,26 @@ // takes in an installQuery as an argument

// returns installation object from database
fetchInstallation: (installQuery) => {
fetchInstallation: async (installQuery) => {
// replace myDB.get with your own database or OEM getter
return myDB.get(installQuery.teamId);
// non enterprise org app lookup
return await myDB.get(installQuery.teamId);
},
// takes in an installation object as an argument
// returns nothing
storeOrgInstallation: (installation) => {
// replace myDB.set with your own database or OEM setter
if (installation.isEnterpriseInstall && installation.enterprise !== undefined) {
// enterprise app, org wide installation
return myDB.set(installation.enterprise.id, installation);
} else {
throw new Error('Failed saving installation data to installationStore');
}
},
// takes in an installQuery as an argument
// installQuery = {teamId: 'string', enterpriseId: 'string', userId: string, conversationId: 'string'};
// returns installation object from database
fetchInstallation: async (installQuery) => {
// replace myDB.get with your own database or OEM getter
// enterprise org app installation lookup
return await myDB.get(installQuery.enterpriseId);
},
},

@@ -200,3 +226,3 @@ });

You can use the the `installationProvider.authorize()` function to fetch data that has been saved in your installation store.
You can use the the `installationProvider.authorize()` function to fetch data that has been saved in your installation store. For Org wide app installations, you can use `installationProvider.orgAuthorize()`

@@ -206,3 +232,4 @@ ```javascript

// installQuery = {teamId: 'string', enterpriseId: 'string', userId: string, conversationId: 'string'};
const result = installer.installationStore.fetchInstallation({teamId:'my-team-ID', enterpriseId:'my-enterprise-ID'});
const result = installer.authorize({teamId:'my-team-ID'});
const orgResult = installer.orgAuthorize({enterpriseId:'my-enterprise-ID'});
/*

@@ -223,3 +250,3 @@ result = {

The `installer.authorize()` method only returns a subset of the installation data returned by the installation store. To fetch the entire saved installation, use the `installer.installationStore.fetchInstallation()` method.
The `installer.authorize()`/`installer.orgAuthorize()` methods only returns a subset of the installation data returned by the installation store. To fetch the entire saved installation, use the `installer.installationStore.fetchInstallation()`/`installer.installationStore.fetchOrgInstallation()` methods.

@@ -230,3 +257,4 @@ ```javascript

// returns an installation object
const result = installer.installationStore.fetchInstallation({teamId:'my-Team-ID'});
const result = installer.installationStore.fetchInstallation({teamId:'my-team-ID', enterpriseId:'my-enterprise-ID'});
const orgResult = installer.installationStore.fetchOrgInstallation({enterpriseId:'my-enterprise-ID'});
```

@@ -233,0 +261,0 @@ </details>

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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