Documentation Index
Fetch the complete documentation index at: https://mintlify.com/openmls/openmls/llms.txt
Use this file to discover all available pages before exploring further.
Overview
There are two ways to join an existing MLS group:
- Welcome Message - Join when invited by an existing member
- External Commit - Join without an invitation (if group allows)
Joining via Welcome
Basic Join
Join a group using a Welcome message:
use openmls::prelude::*;
// Receive Welcome from delivery service
let welcome: Welcome = /* ... */;
let ratchet_tree = /* optional ratchet tree */;
let staged_welcome = StagedWelcome::new_from_welcome(
provider,
&mls_group_join_config,
welcome,
ratchet_tree,
)?;
let mls_group = staged_welcome.into_group(provider)?;
Using the Builder
For advanced inspection before joining:
let join_builder = StagedWelcome::build_from_welcome(
provider,
&mls_group_join_config,
welcome,
)?;
// Inspect the Welcome before accepting
let processed_welcome = join_builder.processed_welcome();
let group_info = processed_welcome.unverified_group_info();
println!("Group ID: {:?}", group_info.group_id());
// Build the staged welcome
let staged_welcome = join_builder
.with_ratchet_tree(ratchet_tree)
.skip_lifetime_validation()
.build()?;
let mls_group = staged_welcome.into_group(provider)?;
Joining via External Commit
Basic External Commit
Join a group without an invitation:
let verifiable_group_info: VerifiableGroupInfo = /* from group */;
let ratchet_tree: RatchetTreeIn = /* group's ratchet tree */;
let (mls_group, commit_message, group_info) =
MlsGroup::external_commit_builder()
.with_ratchet_tree(ratchet_tree)
.with_config(mls_group_join_config)
.build_group(provider, verifiable_group_info, credential_with_key)?
.load_psks(provider.storage())?
.build(provider.rand(), provider.crypto(), &signer, |_| true)?
.finalize(provider)?;
// Send commit_message to the group
// The group is ready to use immediately (with pending commit)
Advanced External Commit
With SelfRemove proposals and custom configuration:
let proposals: Vec<PublicMessageIn> = /* SelfRemove proposals */;
let (mls_group, commit_message, group_info) =
MlsGroup::external_commit_builder()
.with_proposals(proposals) // Include SelfRemove proposals
.with_ratchet_tree(ratchet_tree)
.with_config(mls_group_join_config)
.with_aad(b"additional data".to_vec())
.skip_lifetime_validation()
.build_group(provider, verifiable_group_info, credential_with_key)?
.leaf_node_parameters(
LeafNodeParameters::builder()
.with_capabilities(capabilities)
.build()
)
.load_psks(provider.storage())?
.build(provider.rand(), provider.crypto(), &signer, |_| true)?
.finalize(provider)?;
Method Signatures
StagedWelcome::new_from_welcome
OpenMLS provider for crypto and storage
mls_group_config
&MlsGroupJoinConfig
required
Configuration for joining the group
Welcome message received from the group
Ratchet tree (required if not in Welcome)
Returns: Result<StagedWelcome, WelcomeError>
Location: openmls/src/group/mls_group/creation.rs:474
StagedWelcome::into_group
Converts a staged welcome into an active MlsGroup.
OpenMLS provider for crypto and storage
Returns: Result<MlsGroup, WelcomeError>
Location: openmls/src/group/mls_group/creation.rs:539
ExternalCommitBuilder::build_group
OpenMLS provider for crypto and storage
verifiable_group_info
VerifiableGroupInfo
required
Group information for the target group
credential_with_key
CredentialWithKey
required
Your credential and public key
Returns: Result<CommitBuilder, ExternalCommitBuilderError>
Location: openmls/src/group/mls_group/commit_builder/external_commits.rs:136
Welcome Builder Options
Set the ratchet tree (required if not in Welcome extensions)
Skip validation of leaf node lifetimes
Replace existing group with same ID
External Commit Builder Options
Include SelfRemove proposals from other members
Set the ratchet tree (required if not in GroupInfo)
Set the group configuration
Set additional authenticated data
Skip leaf node lifetime validation
Complete Examples
Joining via Welcome
Receive Welcome message
// Receive from delivery service
let mls_message_in: MlsMessageIn = /* from DS */;
let welcome = mls_message_in.into_welcome()?;
Get ratchet tree
// Either from Welcome extensions or separately
let ratchet_tree = Some(/* ratchet tree */);
Stage the welcome
let staged_welcome = StagedWelcome::new_from_welcome(
provider,
&mls_group_join_config,
welcome,
ratchet_tree,
)?;
Inspect and join
// Optionally inspect
let sender = staged_welcome.welcome_sender()?;
println!("Welcome from: {:?}", sender.credential());
// Join the group
let mut bob_group = staged_welcome.into_group(provider)?;
External Commit Join
Obtain group information
let verifiable_group_info: VerifiableGroupInfo = /* from group */;
let ratchet_tree: RatchetTreeIn = /* from group */;
Build the external commit
let commit_builder = MlsGroup::external_commit_builder()
.with_ratchet_tree(ratchet_tree)
.with_config(mls_group_join_config)
.build_group(provider, verifiable_group_info, credential_with_key)?;
Complete and finalize
let (mut group, commit, group_info) = commit_builder
.load_psks(provider.storage())?
.build(provider.rand(), provider.crypto(), &signer, |_| true)?
.finalize(provider)?;
Send commit to group
// Send commit message to delivery service
// Group members will process it to add you
// Your group has a pending commit
assert!(group.pending_commit().is_some());
Error Handling
Welcome Errors
match StagedWelcome::new_from_welcome(provider, config, welcome, tree) {
Ok(staged) => { /* success */ }
Err(WelcomeError::NoMatchingKeyPackage) => {
// Welcome not for any of our key packages
}
Err(WelcomeError::MissingRatchetTree) => {
// Ratchet tree required but not provided
}
Err(WelcomeError::GroupAlreadyExists) => {
// Group ID already in storage
}
Err(e) => eprintln!("Error: {}", e),
}
External Commit Errors
match external_commit_builder.build_group(provider, info, cred) {
Ok(builder) => { /* continue */ }
Err(ExternalCommitBuilderError::MissingRatchetTree) => {
// Ratchet tree required
}
Err(ExternalCommitBuilderError::MissingExternalPub) => {
// Group doesn't allow external commits
}
Err(e) => eprintln!("Error: {}", e),
}
Important Notes
External Commits: The resulting MlsGroup starts with a pending commit. You must merge this commit for the group to function properly. The commit cannot be cleared - if rejected, discard the group and create a new external commit.
Ratchet Tree: Either the Welcome message must include the ratchet tree extension, or you must provide it separately via with_ratchet_tree().
Key Package Consumption: Joining via Welcome consumes the KeyPackage from storage (unless it has the last_resort extension).
Next Steps