or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-operations.mdauthentication-oauth.mdchat-operations.mdclient-configuration.mdconversation-management.mdcore-api-methods.mderror-handling.mdfile-operations.mdindex.mdpins.mdreactions.mdsearch.mduser-groups.mduser-operations.mdviews-modals.md

authentication-oauth.mddocs/

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

```