# Authentication & OAuth

Handle OAuth flows, token management, and authentication verification.

## Capabilities

### Authentication Testing

Verify authentication tokens and get information about the authenticated user/bot.

```typescript { .api }
/**
 * Test authentication and get basic info about the token
 * @param options - Test parameters (optional)
 * @returns Promise resolving to authentication details
 */
auth.test(options?: AuthTestArguments): Promise<AuthTestResponse>;

interface AuthTestArguments {
  /** Token to test (defaults to client's token) */
  token?: string;
}
```

**Usage Examples:**

```typescript
import { WebClient } from "@slack/web-api";

const web = new WebClient(token);

// Test current token
const authInfo = await web.auth.test();

console.log('Token is valid:', authInfo.ok);
console.log('User/Bot ID:', authInfo.user_id);
console.log('Team ID:', authInfo.team_id);
console.log('Team name:', authInfo.team);
console.log('Is bot:', authInfo.is_enterprise_install);

// Test specific token
const specificAuth = await web.auth.test({
  token: 'xoxb-different-token'
});
```

### Token Revocation

Revoke authentication tokens when no longer needed.

```typescript { .api }
/**
 * Revoke an authentication token
 * @param options - Revocation parameters
 * @returns Promise resolving to revocation confirmation
 */
auth.revoke(options?: AuthRevokeArguments): Promise<AuthRevokeResponse>;

interface AuthRevokeArguments {
  /** Whether to revoke all tokens for this app (default: false) */
  test?: boolean;
  /** Token to revoke (defaults to client's token) */
  token?: string;
}
```

**Usage Examples:**

```typescript
// Revoke current token
const revocationResult = await web.auth.revoke();

if (revocationResult.ok) {
  console.log('Token revoked successfully');
  console.log('Revoked:', revocationResult.revoked);
}

// Test revocation (doesn't actually revoke)
const testRevoke = await web.auth.revoke({
  test: true
});
```

### Team Information

List teams that the authenticated user/bot has access to.

```typescript { .api }
/**
 * List teams the authenticated user is on
 * @param options - List parameters
 * @returns Promise resolving to teams list
 */
auth.teams.list(options?: AuthTeamsListArguments): Promise<AuthTeamsListResponse>;

interface AuthTeamsListArguments {
  /** Cursor for pagination */
  cursor?: string;
  /** Include the number of members on each team */
  include_icon?: boolean;
  /** Maximum number of teams to return */
  limit?: number;
}
```

**Usage Examples:**

```typescript
// List all teams
const teams = await web.auth.teams.list();

console.log(`User is on ${teams.teams.length} teams`);

for (const team of teams.teams) {
  console.log(`Team: ${team.name} (${team.id})`);
}

// Paginate through teams
let cursor;
const allTeams = [];
do {
  const result = await web.auth.teams.list({
    cursor,
    limit: 100
  });
  
  allTeams.push(...result.teams);
  cursor = result.response_metadata?.next_cursor;
} while (cursor);
```

### OAuth V2 Access

Exchange authorization codes for access tokens using OAuth 2.0.

```typescript { .api }
/**
 * Exchange an OAuth authorization code for an access token
 * @param options - OAuth access parameters
 * @returns Promise resolving to OAuth access response
 */
oauth.v2.access(options: OauthV2AccessArguments): Promise<OauthV2AccessResponse>;

interface OauthV2AccessArguments {
  /** Client ID from your Slack app */
  client_id: string;
  /** Client secret from your Slack app */
  client_secret: string;
  /** Authorization code from OAuth redirect */
  code: string;
  /** Redirect URI that was used to generate the code */
  redirect_uri?: string;
}
```

**Usage Examples:**

```typescript
// Exchange authorization code for access token
const oauthResult = await web.oauth.v2.access({
  client_id: process.env.SLACK_CLIENT_ID,
  client_secret: process.env.SLACK_CLIENT_SECRET,
  code: 'authorization-code-from-redirect'
});

if (oauthResult.ok) {
  console.log('OAuth successful!');
  console.log('Access token:', oauthResult.access_token);
  console.log('Token type:', oauthResult.token_type);
  console.log('Scope:', oauthResult.scope);
  console.log('Bot user ID:', oauthResult.bot_user_id);
  console.log('Team ID:', oauthResult.team.id);
  console.log('Team name:', oauthResult.team.name);
  
  // Store the access token for future use
  const userToken = oauthResult.access_token;
  const botToken = oauthResult.access_token; // For bot tokens
}
```

### OAuth V2 Token Exchange

Exchange refresh tokens for new access tokens.

```typescript { .api }
/**
 * Exchange a refresh token for a new access token
 * @param options - Token exchange parameters
 * @returns Promise resolving to new token details
 */
oauth.v2.exchange(options: OauthV2ExchangeArguments): Promise<OauthV2ExchangeResponse>;

interface OauthV2ExchangeArguments {
  /** Client ID from your Slack app */
  client_id: string;
  /** Client secret from your Slack app */
  client_secret: string;
  /** Grant type (should be 'refresh_token') */
  grant_type: string;
  /** Refresh token to exchange */
  refresh_token: string;
}
```

**Usage Examples:**

```typescript
// Exchange refresh token for new access token
const exchangeResult = await web.oauth.v2.exchange({
  client_id: process.env.SLACK_CLIENT_ID,
  client_secret: process.env.SLACK_CLIENT_SECRET,
  grant_type: 'refresh_token',
  refresh_token: storedRefreshToken
});

if (exchangeResult.ok) {
  console.log('Token refreshed!');
  console.log('New access token:', exchangeResult.access_token);
  console.log('New refresh token:', exchangeResult.refresh_token);
  console.log('Expires in:', exchangeResult.expires_in, 'seconds');
  
  // Update stored tokens
  updateStoredTokens({
    access_token: exchangeResult.access_token,
    refresh_token: exchangeResult.refresh_token
  });
}
```

### OpenID Connect

Get OpenID Connect tokens and user information for identity verification.

```typescript { .api }
/**
 * Exchange an authorization code for OpenID Connect tokens
 * @param options - OpenID Connect token parameters
 * @returns Promise resolving to OpenID tokens
 */
openid.connect.token(options: OpenidConnectTokenArguments): Promise<OpenidConnectTokenResponse>;

/**
 * Get user information using OpenID Connect
 * @param options - User info parameters
 * @returns Promise resolving to user information
 */
openid.connect.userInfo(options?: OpenidConnectUserInfoArguments): Promise<OpenidConnectUserInfoResponse>;

interface OpenidConnectTokenArguments {
  /** Client ID from your Slack app */
  client_id: string;
  /** Client secret from your Slack app */
  client_secret: string;
  /** Authorization code from OAuth redirect */
  code: string;
  /** Grant type (should be 'authorization_code') */
  grant_type?: string;
  /** Redirect URI used to generate the code */
  redirect_uri?: string;
}

interface OpenidConnectUserInfoArguments {
  /** OpenID Connect token */
  token?: string;
}
```

**Usage Examples:**

```typescript
// Get OpenID Connect token
const oidcToken = await web.openid.connect.token({
  client_id: process.env.SLACK_CLIENT_ID,
  client_secret: process.env.SLACK_CLIENT_SECRET,
  code: 'authorization-code',
  grant_type: 'authorization_code'
});

if (oidcToken.ok) {
  console.log('OpenID token:', oidcToken.id_token);
  console.log('Access token:', oidcToken.access_token);
}

// Get user info with OpenID Connect
const userInfo = await web.openid.connect.userInfo();

console.log('User ID:', userInfo.sub);
console.log('Email:', userInfo.email);
console.log('Name:', userInfo.name);
console.log('Team ID:', userInfo['https://slack.com/team_id']);
```

### OAuth V1 (Legacy)

Legacy OAuth 1.0 implementation (deprecated - use OAuth V2 instead).

```typescript { .api }
/**
 * Exchange OAuth 1.0 authorization code for access token (DEPRECATED)
 * @param options - OAuth V1 parameters
 * @returns Promise resolving to OAuth V1 response
 */
oauth.access(options: OauthAccessArguments): Promise<OauthAccessResponse>;

interface OauthAccessArguments {
  /** Client ID from your Slack app */
  client_id: string;
  /** Client secret from your Slack app */
  client_secret: string;
  /** Authorization code from OAuth redirect */
  code: string;
  /** Redirect URI used to generate the code */
  redirect_uri?: string;
  /** Set to true to retrieve a bot token */
  single_channel?: boolean;
}
```

**Usage Examples:**

```typescript
// Legacy OAuth V1 (deprecated - use oauth.v2.access instead)
const legacyOauth = await web.oauth.access({
  client_id: process.env.SLACK_CLIENT_ID,
  client_secret: process.env.SLACK_CLIENT_SECRET,
  code: 'authorization-code'
});

console.log('⚠️  Using deprecated OAuth V1 - migrate to OAuth V2');
```

### Complete OAuth Flow Example

A complete example showing how to implement OAuth 2.0 flow in a web application.

```typescript { .api }
/**
 * Example OAuth implementation for web applications
 */
interface OAuthState {
  access_token?: string;
  refresh_token?: string;
  user_id?: string;
  team_id?: string;
  expires_at?: number;
}

class SlackOAuthManager {
  private clientId: string;
  private clientSecret: string;
  private redirectUri: string;
  
  constructor(clientId: string, clientSecret: string, redirectUri: string) {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.redirectUri = redirectUri;
  }
  
  /**
   * Generate OAuth authorization URL
   */
  getAuthorizationUrl(scopes: string[], state?: string): string {
    const params = new URLSearchParams({
      client_id: this.clientId,
      scope: scopes.join(','),
      redirect_uri: this.redirectUri,
      response_type: 'code'
    });
    
    if (state) {
      params.set('state', state);
    }
    
    return `https://slack.com/oauth/v2/authorize?${params.toString()}`;
  }
  
  /**
   * Complete OAuth flow
   */
  async completeOAuth(code: string): Promise<OAuthState> {
    const web = new WebClient();
    
    const result = await web.oauth.v2.access({
      client_id: this.clientId,
      client_secret: this.clientSecret,
      code,
      redirect_uri: this.redirectUri
    });
    
    return {
      access_token: result.access_token,
      refresh_token: result.refresh_token,
      user_id: result.authed_user?.id,
      team_id: result.team?.id,
      expires_at: result.expires_in ? Date.now() + (result.expires_in * 1000) : undefined
    };
  }
  
  /**
   * Refresh access token
   */
  async refreshToken(refreshToken: string): Promise<OAuthState> {
    const web = new WebClient();
    
    const result = await web.oauth.v2.exchange({
      client_id: this.clientId,
      client_secret: this.clientSecret,
      grant_type: 'refresh_token',
      refresh_token: refreshToken
    });
    
    return {
      access_token: result.access_token,
      refresh_token: result.refresh_token,
      expires_at: result.expires_in ? Date.now() + (result.expires_in * 1000) : undefined
    };
  }
}
```

**Usage Examples:**

```typescript
// Initialize OAuth manager
const oauthManager = new SlackOAuthManager(
  process.env.SLACK_CLIENT_ID,
  process.env.SLACK_CLIENT_SECRET,
  'https://myapp.com/oauth/callback'
);

// Step 1: Redirect user to Slack for authorization
const authUrl = oauthManager.getAuthorizationUrl([
  'chat:write',
  'channels:read',
  'users:read'
], 'random-state-string');

console.log('Redirect user to:', authUrl);

// Step 2: Handle OAuth callback
app.get('/oauth/callback', async (req, res) => {
  const { code, state } = req.query;
  
  try {
    const oauthState = await oauthManager.completeOAuth(code);
    
    // Store tokens securely
    await storeUserTokens(oauthState.user_id, oauthState);
    
    res.redirect('/success');
  } catch (error) {
    console.error('OAuth error:', error);
    res.redirect('/error');
  }
});

// Step 3: Use stored tokens
async function makeSlackCall(userId: string) {
  const tokens = await getUserTokens(userId);
  
  // Check if token needs refresh
  if (tokens.expires_at && Date.now() > tokens.expires_at) {
    const refreshed = await oauthManager.refreshToken(tokens.refresh_token);
    await storeUserTokens(userId, refreshed);
    tokens.access_token = refreshed.access_token;
  }
  
  const web = new WebClient(tokens.access_token);
  return await web.chat.postMessage({
    channel: '#general',
    text: 'Hello from OAuth!'
  });
}
```

## Types

```typescript { .api }
interface AuthTestResponse extends WebAPICallResult {
  url: string;
  team: string;
  user: string;
  team_id: string;
  user_id: string;
  bot_id?: string;
  is_enterprise_install?: boolean;
}

interface OauthV2AccessResponse extends WebAPICallResult {
  access_token: string;
  token_type: string;
  scope: string;
  bot_user_id?: string;
  app_id: string;
  team: {
    id: string;
    name: string;
  };
  enterprise?: {
    id: string;
    name: string;
  };
  authed_user?: {
    id: string;
    scope?: string;
    access_token?: string;
    token_type?: string;
  };
  refresh_token?: string;
  expires_in?: number;
}

interface AuthTeamsListResponse extends WebAPICallResult {
  teams: {
    id: string;
    name: string;
    icon?: {
      image_34?: string;
      image_44?: string;
      image_68?: string;
      image_88?: string;
      image_102?: string;
      image_132?: string;
      image_230?: string;
    };
  }[];
  response_metadata?: {
    next_cursor?: string;
  };
}

interface OpenidConnectUserInfoResponse extends WebAPICallResult {
  sub: string;
  email: string;
  email_verified: boolean;
  name: string;
  picture: string;
  given_name: string;
  family_name: string;
  locale: string;
  'https://slack.com/team_id': string;
  'https://slack.com/user_id': string;
}
```