Slack Auth & Security
OAuth 2.0 Flow
Bot Token vs User Token
Bot Token (xoxb- ):
-
Performs actions as the bot user
-
Requires bot scopes
-
Recommended for most operations
User Token (xoxp- ):
-
Acts on behalf of specific user
-
Requires user scopes
-
Used for user-specific operations
Basic OAuth Flow
import "github.com/slack-go/slack"
// Step 1: Generate authorization URL state := generateRandomState() authURL := fmt.Sprintf( "https://slack.com/oauth/v2/authorize?client_id=%s&scope=%s&state=%s", clientID, "chat:write,channels:read", state, )
See oauth-flow.md for complete OAuth implementation.
Token Management
Storing Tokens Securely
// NEVER hardcode tokens // Use environment variables or secrets manager token := os.Getenv("SLACK_BOT_TOKEN") api := slack.New(token)
Token Rotation
// Rotate tokens periodically newToken, err := api.RotateTokens(refreshToken) if err != nil { return err }
// Update stored token storeToken(newToken)
See token-management.md for storage strategies and rotation patterns.
Scopes and Permissions
Required Scopes by Operation
Messaging:
-
chat:write
-
Send messages
-
chat:write.public
-
Post to channels bot isn't in
Channels:
-
channels:read
-
View public channels
-
channels:manage
-
Create/manage channels
-
groups:read
-
View private channels
Users:
-
users:read
-
View users
-
users:read.email
-
View user emails
See scopes-permissions.md for comprehensive scope guide.
Security Best Practices
- Request Verification
Always verify requests from Slack:
import "github.com/slack-go/slack"
func verifySlackRequest(r *http.Request, signingSecret string) bool { verifier, err := slack.NewSecretsVerifier(r.Header, signingSecret) if err != nil { return false }
body, _ := ioutil.ReadAll(r.Body)
verifier.Write(body)
return verifier.Ensure() == nil
}
- HTTPS Only
Never use HTTP endpoints for webhooks:
- Token Storage
-
Use environment variables for development
-
Use secrets managers (AWS Secrets Manager, HashiCorp Vault) for production
-
Encrypt tokens at rest
-
Never commit tokens to version control
- Rate Limiting
Implement rate limiting to avoid abuse:
type RateLimiter struct { requests map[string][]time.Time mu sync.Mutex }
func (rl *RateLimiter) Allow(userID string, maxRequests int, window time.Duration) bool { rl.mu.Lock() defer rl.mu.Unlock()
now := time.Now()
cutoff := now.Add(-window)
// Remove old requests
var validRequests []time.Time
for _, t := range rl.requests[userID] {
if t.After(cutoff) {
validRequests = append(validRequests, t)
}
}
if len(validRequests) >= maxRequests {
return false
}
rl.requests[userID] = append(validRequests, now)
return true
}
Multi-Workspace Installations
Token Per Workspace
Store tokens separately for each workspace:
type WorkspaceToken struct { TeamID string BotToken string BotUserID string InstalledAt time.Time }
func getAPIForTeam(teamID string) (*slack.Client, error) { token, err := loadTokenForTeam(teamID) if err != nil { return nil, err } return slack.New(token.BotToken), nil }
App Manifest API
Programmatically configure apps:
manifest := &slack.Manifest{ DisplayInformation: slack.ManifestDisplayInformation{ Name: "My Bot", Description: "Helpful bot", }, Features: slack.ManifestFeatures{ BotUser: &slack.ManifestBotUser{ DisplayName: "mybot", AlwaysOnline: true, }, }, OAuthConfig: slack.ManifestOAuthConfig{ Scopes: slack.ManifestOAuthScopes{ Bot: []string{"chat:write", "channels:read"}, }, }, }
_, err := api.CreateManifest(manifest)
See manifest-api.md for manifest patterns.
Production Checklist
See security-checklist.md for comprehensive security audit:
-
✅ HTTPS endpoints
-
✅ Request signature verification
-
✅ Token encryption at rest
-
✅ Rate limiting
-
✅ Audit logging
-
✅ Error handling (don't leak sensitive info)
-
✅ Regular token rotation
Common Pitfalls
-
Hardcoding tokens in code
-
Not verifying request signatures
-
Using HTTP instead of HTTPS
-
Storing tokens in plain text
-
Not implementing rate limiting
-
Exposing sensitive errors to users