Skip to content

Commit e5cb7b0

Browse files
authored
fix(slack): remove unused files:write and users:read.email scopes (#3061)
Slack marketplace review flagged that the OAuth URL requested files:write and users:read.email scopes that weren't declared in the marketplace submission. Neither scope is actually exercised by the code: there are no files.upload calls, and the only consumers of users:read.email (getSlackUserEmail / getSlackUserEmailFromInstallation) had no callers, so they're removed too.
1 parent 1d88d32 commit e5cb7b0

2 files changed

Lines changed: 1 addition & 54 deletions

File tree

apps/web/src/lib/integrations/slack-service.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ export const SLACK_SCOPES = [
4040
'channels:read',
4141
'chat:write',
4242
'files:read',
43-
'files:write',
4443
'groups:history',
4544
'groups:read',
4645
'im:history',
@@ -51,7 +50,6 @@ export const SLACK_SCOPES = [
5150
'reactions:write',
5251
'team:read',
5352
'users:read',
54-
'users:read.email',
5553
];
5654

5755
export function getMissingSlackScopes(installedScopes: string[] | null): string[] {

apps/web/src/lib/slack-bot/slack-utils.ts

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { WebClient, type SlackEvent } from '@slack/web-api';
1+
import type { WebClient, SlackEvent } from '@slack/web-api';
22

33
export function isRecord(value: unknown): value is Record<string, unknown> {
44
return typeof value === 'object' && value !== null;
@@ -38,57 +38,6 @@ export async function getSlackUserDisplayAndRealName(
3838
}
3939
}
4040

41-
/**
42-
* Get a Slack user's email address.
43-
* Requires the `users:read.email` scope on the Slack app.
44-
*
45-
* @param client - The Slack WebClient initialized with the workspace access token
46-
* @param userId - The Slack user ID (e.g., "U1234567890")
47-
* @returns The user's email address, or undefined if not available
48-
*/
49-
export async function getSlackUserEmail(
50-
client: WebClient,
51-
userId: string
52-
): Promise<string | undefined> {
53-
try {
54-
const result = await client.users.info({ user: userId });
55-
56-
if (!result.ok || !result.user) {
57-
return undefined;
58-
}
59-
60-
return result.user.profile?.email;
61-
} catch {
62-
return undefined;
63-
}
64-
}
65-
66-
/**
67-
* Get a Slack user's email using an installation's access token.
68-
* Requires the `users:read.email` scope on the Slack app.
69-
*
70-
* @param installation - The Slack installation with metadata containing access_token
71-
* @param userId - The Slack user ID (e.g., "U1234567890")
72-
* @returns The user's email address, or undefined if not available
73-
*/
74-
export async function getSlackUserEmailFromInstallation(
75-
installation: { metadata: unknown } | null,
76-
userId: string
77-
): Promise<string | undefined> {
78-
const metadata = installation?.metadata;
79-
if (!isRecord(metadata)) {
80-
return undefined;
81-
}
82-
83-
const accessToken = metadata['access_token'];
84-
if (typeof accessToken !== 'string') {
85-
return undefined;
86-
}
87-
88-
const client = new WebClient(accessToken);
89-
return getSlackUserEmail(client, userId);
90-
}
91-
9241
export function formatSlackUserDisplayAndRealName(
9342
displayName: string,
9443
realName: string | undefined

0 commit comments

Comments
 (0)