docs/channels/access-groups.md
Access groups are named sender lists you define once and reference from channel allowlists with accessGroup:<name>.
Use them when the same people should be allowed across several message channels, or when one trusted set should apply to both DMs and group sender authorization.
Access groups do not grant access by themselves. A group only matters when an allowlist field references it.
Static sender groups use type: "message.senders".
{
accessGroups: {
operators: {
type: "message.senders",
members: {
"*": ["global-owner-id"],
discord: ["discord:123456789012345678"],
telegram: ["987654321"],
whatsapp: ["+15551234567"],
},
},
},
}
Member lists are keyed by message-channel id:
| Key | Meaning |
|---|---|
"*" | Shared entries checked for every message channel that references group. |
discord | Entries checked only for Discord allowlist matching. |
telegram | Entries checked only for Telegram allowlist matching. |
whatsapp | Entries checked only for WhatsApp allowlist matching. |
Entries are matched with the destination channel's normal allowFrom rules. OpenClaw does not translate sender ids between channels. If Alice has a Telegram id and a Discord id, list both ids under the appropriate keys.
Reference a group with accessGroup:<name> anywhere the message channel path supports sender allowlists.
DM allowlist example:
{
accessGroups: {
operators: {
type: "message.senders",
members: {
discord: ["discord:123456789012345678"],
telegram: ["987654321"],
},
},
},
channels: {
discord: {
dmPolicy: "allowlist",
allowFrom: ["accessGroup:operators"],
},
telegram: {
dmPolicy: "allowlist",
allowFrom: ["accessGroup:operators"],
},
},
}
Group sender allowlist example:
{
accessGroups: {
oncall: {
type: "message.senders",
members: {
whatsapp: ["+15551234567"],
googlechat: ["users/1234567890"],
},
},
},
channels: {
whatsapp: {
groupPolicy: "allowlist",
groupAllowFrom: ["accessGroup:oncall"],
},
googlechat: {
spaces: {
"spaces/AAA": {
users: ["accessGroup:oncall"],
},
},
},
},
}
You can mix groups and direct entries:
{
channels: {
discord: {
dmPolicy: "allowlist",
allowFrom: ["accessGroup:operators", "discord:123456789012345678"],
},
},
}
Access groups are available in shared message-channel authorization paths, including:
channels.<channel>.allowFromchannels.<channel>.groupAllowFromChannel support depends on whether that channel is wired through the shared OpenClaw sender-authorization helpers. Current bundled support includes Discord, Google Chat, Nostr, WhatsApp, Zalo, and Zalo Personal. Static message.senders groups are designed to be channel-agnostic, so new message channels should support them by using the shared plugin SDK helpers instead of custom allowlist expansion.
Discord also supports a dynamic access group type:
{
accessGroups: {
maintainers: {
type: "discord.channelAudience",
guildId: "1456350064065904867",
channelId: "1456744319972282449",
membership: "canViewChannel",
},
},
channels: {
discord: {
dmPolicy: "allowlist",
allowFrom: ["accessGroup:maintainers"],
},
},
}
discord.channelAudience means "allow Discord DM senders who can currently view this guild channel." OpenClaw resolves the sender through Discord at authorization time and applies Discord ViewChannel permission rules.
Use this when a Discord channel is already the source of truth for a team, such as #maintainers or #on-call.
Requirements and failure behavior:
Missing Access, the sender cannot be resolved as a guild member, or the channel belongs to another guild.More Discord-specific examples: Discord access control
dmPolicy: "open" still requires "*" in the effective DM allowlist. Referencing an access group is not the same as public access.allowFrom contains accessGroup:operators and accessGroups.operators is absent, that entry authorizes nobody.If a sender should match but is blocked:
accessGroup:<name> reference.accessGroups.<name>.type is correct."*".Run openclaw doctor after editing access-control config. It catches many invalid allowlist and policy combinations before runtime.