Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,13 +300,14 @@ enable=true
```toml
[slack]
[slack.test]
Token="yourslacktoken"
PrefixMessagesWithNick=true
Token="xoxb-yourslackbottoken"
AppToken="xapp-yourapptoken"

[discord]
[discord.test]
Token="yourdiscordtoken"
Server="yourdiscordservername"
AutoWebhooks=true

[general]
RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
Expand All @@ -324,6 +325,52 @@ RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
channel = "general"
```

> **Setup requirements for Slack and Discord are detailed below.** Both platforms have tightened their API access in recent years, so your bot apps need specific scopes and intents configured before matterbridge can function.

#### Slack app setup

Matterbridge uses **Socket Mode** to connect to Slack. You need both a Bot Token (`xoxb-`) and an App-Level Token (`xapp-`).

1. Create a Slack app at <https://api.slack.com/apps>
2. Enable **Socket Mode** under *Settings > Socket Mode*
3. Create an **App-Level Token** with the `connections:write` scope — this is your `AppToken`
4. Under *OAuth & Permissions*, add these **Bot Token Scopes**:

| Scope | Purpose |
|-------|---------|
| `channels:history` | Read messages in public channels |
| `channels:read` | List and find public channels |
| `chat:write` | Post messages |
| `chat:write.customize` | Post messages with custom username and avatar (required for username spoofing) |
| `files:read` | Access shared files |
| `files:write` | Upload files |
| `groups:history` | Read messages in private channels |
| `groups:read` | List and find private channels |
| `reactions:read` | Read emoji reactions |
| `users:read` | Look up user info for display names and avatars |

5. Under *Event Subscriptions > Subscribe to bot events*, add:
- `message.channels` — messages in public channels
- `message.groups` — messages in private channels
- `member_joined_channel` — channel membership changes

6. Install the app to your workspace. The **Bot User OAuth Token** is your `Token`.

> **Note:** Without the `chat:write.customize` scope, all bridged messages will appear under the bot's own name instead of showing the original sender's username and avatar.

#### Discord bot setup

1. Create a bot at <https://discord.com/developers/applications>
2. Under *Bot > Privileged Gateway Intents*, enable:
- **Message Content Intent** — required to read message text, embeds, and attachments
- **Server Members Intent** — required for member/nick resolution
3. Under *OAuth2 > URL Generator*, select the `bot` scope with these **Bot Permissions**:
- **Read Messages/View Channels**
- **Send Messages**
- **Manage Webhooks** — required when using `AutoWebhooks=true` (recommended for username/avatar spoofing)
- **Manage Roles** — optional, allows role mentions to display with names instead of IDs
4. Use the generated URL to invite the bot to your server

## Running

See [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
Expand Down
1 change: 1 addition & 0 deletions bridge/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ type Protocol struct {
TeamID string // msteams
TenantID string // msteams
Token string // gitter, slack, discord, api, matrix
AppToken string // slack
Topic string // zulip
URL string // mattermost, slack // DEPRECATED
UseAPI bool // mattermost, slack
Expand Down
7 changes: 3 additions & 4 deletions bridge/discord/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,9 @@ func (b *Bdiscord) Connect() error {
return err
}
b.Log.Info("Connection succeeded")
// Add privileged intent for guild member tracking. This is needed to track nicks
// for display names and @mention translation
b.c.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged |
discordgo.IntentsGuildMembers)
b.c.Identify.Intents = discordgo.IntentsAllWithoutPrivileged |
discordgo.IntentsGuildMembers |
discordgo.IntentMessageContent

err = b.c.Open()
if err != nil {
Expand Down
13 changes: 6 additions & 7 deletions bridge/discord/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ func (b *Bdiscord) getNick(user *discordgo.User, guildID string) string {
defer b.membersMutex.RUnlock()

if member, ok := b.userMemberMap[user.ID]; ok {
if member.Nick != "" {
// Only return if nick is set.
return member.Nick
// Use Discord's display name priority: server nick > global display name > username
if name := member.DisplayName(); name != "" {
return name
}
// Otherwise return username.
return user.Username
}

Expand All @@ -57,9 +56,9 @@ func (b *Bdiscord) getNick(user *discordgo.User, guildID string) string {
}
b.userMemberMap[user.ID] = member
b.nickMemberMap[member.User.Username] = member
if member.Nick != "" {
b.nickMemberMap[member.Nick] = member
return member.Nick
if name := member.DisplayName(); name != "" {
b.nickMemberMap[name] = member
return name
}
return user.Username
}
Expand Down
Loading