0
# Authentication & OAuth
1
2
Handle OAuth flows, token management, and authentication verification.
3
4
## Capabilities
5
6
### Authentication Testing
7
8
Verify authentication tokens and get information about the authenticated user/bot.
9
10
```typescript { .api }
11
/**
12
* Test authentication and get basic info about the token
13
* @param options - Test parameters (optional)
14
* @returns Promise resolving to authentication details
15
*/
16
auth.test(options?: AuthTestArguments): Promise<AuthTestResponse>;
17
18
interface AuthTestArguments {
19
/** Token to test (defaults to client's token) */
20
token?: string;
21
}
22
```
23
24
**Usage Examples:**
25
26
```typescript
27
import { WebClient } from "@slack/web-api";
28
29
const web = new WebClient(token);
30
31
// Test current token
32
const authInfo = await web.auth.test();
33
34
console.log('Token is valid:', authInfo.ok);
35
console.log('User/Bot ID:', authInfo.user_id);
36
console.log('Team ID:', authInfo.team_id);
37
console.log('Team name:', authInfo.team);
38
console.log('Is bot:', authInfo.is_enterprise_install);
39
40
// Test specific token
41
const specificAuth = await web.auth.test({
42
token: 'xoxb-different-token'
43
});
44
```
45
46
### Token Revocation
47
48
Revoke authentication tokens when no longer needed.
49
50
```typescript { .api }
51
/**
52
* Revoke an authentication token
53
* @param options - Revocation parameters
54
* @returns Promise resolving to revocation confirmation
55
*/
56
auth.revoke(options?: AuthRevokeArguments): Promise<AuthRevokeResponse>;
57
58
interface AuthRevokeArguments {
59
/** Whether to revoke all tokens for this app (default: false) */
60
test?: boolean;
61
/** Token to revoke (defaults to client's token) */
62
token?: string;
63
}
64
```
65
66
**Usage Examples:**
67
68
```typescript
69
// Revoke current token
70
const revocationResult = await web.auth.revoke();
71
72
if (revocationResult.ok) {
73
console.log('Token revoked successfully');
74
console.log('Revoked:', revocationResult.revoked);
75
}
76
77
// Test revocation (doesn't actually revoke)
78
const testRevoke = await web.auth.revoke({
79
test: true
80
});
81
```
82
83
### Team Information
84
85
List teams that the authenticated user/bot has access to.
86
87
```typescript { .api }
88
/**
89
* List teams the authenticated user is on
90
* @param options - List parameters
91
* @returns Promise resolving to teams list
92
*/
93
auth.teams.list(options?: AuthTeamsListArguments): Promise<AuthTeamsListResponse>;
94
95
interface AuthTeamsListArguments {
96
/** Cursor for pagination */
97
cursor?: string;
98
/** Include the number of members on each team */
99
include_icon?: boolean;
100
/** Maximum number of teams to return */
101
limit?: number;
102
}
103
```
104
105
**Usage Examples:**
106
107
```typescript
108
// List all teams
109
const teams = await web.auth.teams.list();
110
111
console.log(`User is on ${teams.teams.length} teams`);
112
113
for (const team of teams.teams) {
114
console.log(`Team: ${team.name} (${team.id})`);
115
}
116
117
// Paginate through teams
118
let cursor;
119
const allTeams = [];
120
do {
121
const result = await web.auth.teams.list({
122
cursor,
123
limit: 100
124
});
125
126
allTeams.push(...result.teams);
127
cursor = result.response_metadata?.next_cursor;
128
} while (cursor);
129
```
130
131
### OAuth V2 Access
132
133
Exchange authorization codes for access tokens using OAuth 2.0.
134
135
```typescript { .api }
136
/**
137
* Exchange an OAuth authorization code for an access token
138
* @param options - OAuth access parameters
139
* @returns Promise resolving to OAuth access response
140
*/
141
oauth.v2.access(options: OauthV2AccessArguments): Promise<OauthV2AccessResponse>;
142
143
interface OauthV2AccessArguments {
144
/** Client ID from your Slack app */
145
client_id: string;
146
/** Client secret from your Slack app */
147
client_secret: string;
148
/** Authorization code from OAuth redirect */
149
code: string;
150
/** Redirect URI that was used to generate the code */
151
redirect_uri?: string;
152
}
153
```
154
155
**Usage Examples:**
156
157
```typescript
158
// Exchange authorization code for access token
159
const oauthResult = await web.oauth.v2.access({
160
client_id: process.env.SLACK_CLIENT_ID,
161
client_secret: process.env.SLACK_CLIENT_SECRET,
162
code: 'authorization-code-from-redirect'
163
});
164
165
if (oauthResult.ok) {
166
console.log('OAuth successful!');
167
console.log('Access token:', oauthResult.access_token);
168
console.log('Token type:', oauthResult.token_type);
169
console.log('Scope:', oauthResult.scope);
170
console.log('Bot user ID:', oauthResult.bot_user_id);
171
console.log('Team ID:', oauthResult.team.id);
172
console.log('Team name:', oauthResult.team.name);
173
174
// Store the access token for future use
175
const userToken = oauthResult.access_token;
176
const botToken = oauthResult.access_token; // For bot tokens
177
}
178
```
179
180
### OAuth V2 Token Exchange
181
182
Exchange refresh tokens for new access tokens.
183
184
```typescript { .api }
185
/**
186
* Exchange a refresh token for a new access token
187
* @param options - Token exchange parameters
188
* @returns Promise resolving to new token details
189
*/
190
oauth.v2.exchange(options: OauthV2ExchangeArguments): Promise<OauthV2ExchangeResponse>;
191
192
interface OauthV2ExchangeArguments {
193
/** Client ID from your Slack app */
194
client_id: string;
195
/** Client secret from your Slack app */
196
client_secret: string;
197
/** Grant type (should be 'refresh_token') */
198
grant_type: string;
199
/** Refresh token to exchange */
200
refresh_token: string;
201
}
202
```
203
204
**Usage Examples:**
205
206
```typescript
207
// Exchange refresh token for new access token
208
const exchangeResult = await web.oauth.v2.exchange({
209
client_id: process.env.SLACK_CLIENT_ID,
210
client_secret: process.env.SLACK_CLIENT_SECRET,
211
grant_type: 'refresh_token',
212
refresh_token: storedRefreshToken
213
});
214
215
if (exchangeResult.ok) {
216
console.log('Token refreshed!');
217
console.log('New access token:', exchangeResult.access_token);
218
console.log('New refresh token:', exchangeResult.refresh_token);
219
console.log('Expires in:', exchangeResult.expires_in, 'seconds');
220
221
// Update stored tokens
222
updateStoredTokens({
223
access_token: exchangeResult.access_token,
224
refresh_token: exchangeResult.refresh_token
225
});
226
}
227
```
228
229
### OpenID Connect
230
231
Get OpenID Connect tokens and user information for identity verification.
232
233
```typescript { .api }
234
/**
235
* Exchange an authorization code for OpenID Connect tokens
236
* @param options - OpenID Connect token parameters
237
* @returns Promise resolving to OpenID tokens
238
*/
239
openid.connect.token(options: OpenidConnectTokenArguments): Promise<OpenidConnectTokenResponse>;
240
241
/**
242
* Get user information using OpenID Connect
243
* @param options - User info parameters
244
* @returns Promise resolving to user information
245
*/
246
openid.connect.userInfo(options?: OpenidConnectUserInfoArguments): Promise<OpenidConnectUserInfoResponse>;
247
248
interface OpenidConnectTokenArguments {
249
/** Client ID from your Slack app */
250
client_id: string;
251
/** Client secret from your Slack app */
252
client_secret: string;
253
/** Authorization code from OAuth redirect */
254
code: string;
255
/** Grant type (should be 'authorization_code') */
256
grant_type?: string;
257
/** Redirect URI used to generate the code */
258
redirect_uri?: string;
259
}
260
261
interface OpenidConnectUserInfoArguments {
262
/** OpenID Connect token */
263
token?: string;
264
}
265
```
266
267
**Usage Examples:**
268
269
```typescript
270
// Get OpenID Connect token
271
const oidcToken = await web.openid.connect.token({
272
client_id: process.env.SLACK_CLIENT_ID,
273
client_secret: process.env.SLACK_CLIENT_SECRET,
274
code: 'authorization-code',
275
grant_type: 'authorization_code'
276
});
277
278
if (oidcToken.ok) {
279
console.log('OpenID token:', oidcToken.id_token);
280
console.log('Access token:', oidcToken.access_token);
281
}
282
283
// Get user info with OpenID Connect
284
const userInfo = await web.openid.connect.userInfo();
285
286
console.log('User ID:', userInfo.sub);
287
console.log('Email:', userInfo.email);
288
console.log('Name:', userInfo.name);
289
console.log('Team ID:', userInfo['https://slack.com/team_id']);
290
```
291
292
### OAuth V1 (Legacy)
293
294
Legacy OAuth 1.0 implementation (deprecated - use OAuth V2 instead).
295
296
```typescript { .api }
297
/**
298
* Exchange OAuth 1.0 authorization code for access token (DEPRECATED)
299
* @param options - OAuth V1 parameters
300
* @returns Promise resolving to OAuth V1 response
301
*/
302
oauth.access(options: OauthAccessArguments): Promise<OauthAccessResponse>;
303
304
interface OauthAccessArguments {
305
/** Client ID from your Slack app */
306
client_id: string;
307
/** Client secret from your Slack app */
308
client_secret: string;
309
/** Authorization code from OAuth redirect */
310
code: string;
311
/** Redirect URI used to generate the code */
312
redirect_uri?: string;
313
/** Set to true to retrieve a bot token */
314
single_channel?: boolean;
315
}
316
```
317
318
**Usage Examples:**
319
320
```typescript
321
// Legacy OAuth V1 (deprecated - use oauth.v2.access instead)
322
const legacyOauth = await web.oauth.access({
323
client_id: process.env.SLACK_CLIENT_ID,
324
client_secret: process.env.SLACK_CLIENT_SECRET,
325
code: 'authorization-code'
326
});
327
328
console.log('⚠️ Using deprecated OAuth V1 - migrate to OAuth V2');
329
```
330
331
### Complete OAuth Flow Example
332
333
A complete example showing how to implement OAuth 2.0 flow in a web application.
334
335
```typescript { .api }
336
/**
337
* Example OAuth implementation for web applications
338
*/
339
interface OAuthState {
340
access_token?: string;
341
refresh_token?: string;
342
user_id?: string;
343
team_id?: string;
344
expires_at?: number;
345
}
346
347
class SlackOAuthManager {
348
private clientId: string;
349
private clientSecret: string;
350
private redirectUri: string;
351
352
constructor(clientId: string, clientSecret: string, redirectUri: string) {
353
this.clientId = clientId;
354
this.clientSecret = clientSecret;
355
this.redirectUri = redirectUri;
356
}
357
358
/**
359
* Generate OAuth authorization URL
360
*/
361
getAuthorizationUrl(scopes: string[], state?: string): string {
362
const params = new URLSearchParams({
363
client_id: this.clientId,
364
scope: scopes.join(','),
365
redirect_uri: this.redirectUri,
366
response_type: 'code'
367
});
368
369
if (state) {
370
params.set('state', state);
371
}
372
373
return `https://slack.com/oauth/v2/authorize?${params.toString()}`;
374
}
375
376
/**
377
* Complete OAuth flow
378
*/
379
async completeOAuth(code: string): Promise<OAuthState> {
380
const web = new WebClient();
381
382
const result = await web.oauth.v2.access({
383
client_id: this.clientId,
384
client_secret: this.clientSecret,
385
code,
386
redirect_uri: this.redirectUri
387
});
388
389
return {
390
access_token: result.access_token,
391
refresh_token: result.refresh_token,
392
user_id: result.authed_user?.id,
393
team_id: result.team?.id,
394
expires_at: result.expires_in ? Date.now() + (result.expires_in * 1000) : undefined
395
};
396
}
397
398
/**
399
* Refresh access token
400
*/
401
async refreshToken(refreshToken: string): Promise<OAuthState> {
402
const web = new WebClient();
403
404
const result = await web.oauth.v2.exchange({
405
client_id: this.clientId,
406
client_secret: this.clientSecret,
407
grant_type: 'refresh_token',
408
refresh_token: refreshToken
409
});
410
411
return {
412
access_token: result.access_token,
413
refresh_token: result.refresh_token,
414
expires_at: result.expires_in ? Date.now() + (result.expires_in * 1000) : undefined
415
};
416
}
417
}
418
```
419
420
**Usage Examples:**
421
422
```typescript
423
// Initialize OAuth manager
424
const oauthManager = new SlackOAuthManager(
425
process.env.SLACK_CLIENT_ID,
426
process.env.SLACK_CLIENT_SECRET,
427
'https://myapp.com/oauth/callback'
428
);
429
430
// Step 1: Redirect user to Slack for authorization
431
const authUrl = oauthManager.getAuthorizationUrl([
432
'chat:write',
433
'channels:read',
434
'users:read'
435
], 'random-state-string');
436
437
console.log('Redirect user to:', authUrl);
438
439
// Step 2: Handle OAuth callback
440
app.get('/oauth/callback', async (req, res) => {
441
const { code, state } = req.query;
442
443
try {
444
const oauthState = await oauthManager.completeOAuth(code);
445
446
// Store tokens securely
447
await storeUserTokens(oauthState.user_id, oauthState);
448
449
res.redirect('/success');
450
} catch (error) {
451
console.error('OAuth error:', error);
452
res.redirect('/error');
453
}
454
});
455
456
// Step 3: Use stored tokens
457
async function makeSlackCall(userId: string) {
458
const tokens = await getUserTokens(userId);
459
460
// Check if token needs refresh
461
if (tokens.expires_at && Date.now() > tokens.expires_at) {
462
const refreshed = await oauthManager.refreshToken(tokens.refresh_token);
463
await storeUserTokens(userId, refreshed);
464
tokens.access_token = refreshed.access_token;
465
}
466
467
const web = new WebClient(tokens.access_token);
468
return await web.chat.postMessage({
469
channel: '#general',
470
text: 'Hello from OAuth!'
471
});
472
}
473
```
474
475
## Types
476
477
```typescript { .api }
478
interface AuthTestResponse extends WebAPICallResult {
479
url: string;
480
team: string;
481
user: string;
482
team_id: string;
483
user_id: string;
484
bot_id?: string;
485
is_enterprise_install?: boolean;
486
}
487
488
interface OauthV2AccessResponse extends WebAPICallResult {
489
access_token: string;
490
token_type: string;
491
scope: string;
492
bot_user_id?: string;
493
app_id: string;
494
team: {
495
id: string;
496
name: string;
497
};
498
enterprise?: {
499
id: string;
500
name: string;
501
};
502
authed_user?: {
503
id: string;
504
scope?: string;
505
access_token?: string;
506
token_type?: string;
507
};
508
refresh_token?: string;
509
expires_in?: number;
510
}
511
512
interface AuthTeamsListResponse extends WebAPICallResult {
513
teams: {
514
id: string;
515
name: string;
516
icon?: {
517
image_34?: string;
518
image_44?: string;
519
image_68?: string;
520
image_88?: string;
521
image_102?: string;
522
image_132?: string;
523
image_230?: string;
524
};
525
}[];
526
response_metadata?: {
527
next_cursor?: string;
528
};
529
}
530
531
interface OpenidConnectUserInfoResponse extends WebAPICallResult {
532
sub: string;
533
email: string;
534
email_verified: boolean;
535
name: string;
536
picture: string;
537
given_name: string;
538
family_name: string;
539
locale: string;
540
'https://slack.com/team_id': string;
541
'https://slack.com/user_id': string;
542
}
543
```