Skip to main content

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:
  1. Welcome Message - Join when invited by an existing member
  2. 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

provider
&Provider
required
OpenMLS provider for crypto and storage
mls_group_config
&MlsGroupJoinConfig
required
Configuration for joining the group
welcome
Welcome
required
Welcome message received from the group
ratchet_tree
Option<RatchetTreeIn>
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.
provider
&Provider
required
OpenMLS provider for crypto and storage
Returns: Result<MlsGroup, WelcomeError> Location: openmls/src/group/mls_group/creation.rs:539

ExternalCommitBuilder::build_group

provider
&Provider
required
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

with_ratchet_tree
RatchetTreeIn
Set the ratchet tree (required if not in Welcome extensions)
skip_lifetime_validation
bool
Skip validation of leaf node lifetimes
replace_old_group
bool
Replace existing group with same ID

External Commit Builder Options

with_proposals
Vec<PublicMessageIn>
Include SelfRemove proposals from other members
with_ratchet_tree
RatchetTreeIn
Set the ratchet tree (required if not in GroupInfo)
with_config
MlsGroupJoinConfig
Set the group configuration
with_aad
Vec<u8>
Set additional authenticated data
skip_lifetime_validation
bool
Skip leaf node lifetime validation

Complete Examples

Joining via Welcome

1

Receive Welcome message

// Receive from delivery service
let mls_message_in: MlsMessageIn = /* from DS */;
let welcome = mls_message_in.into_welcome()?;
2

Get ratchet tree

// Either from Welcome extensions or separately
let ratchet_tree = Some(/* ratchet tree */);
3

Stage the welcome

let staged_welcome = StagedWelcome::new_from_welcome(
    provider,
    &mls_group_join_config,
    welcome,
    ratchet_tree,
)?;
4

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

1

Obtain group information

let verifiable_group_info: VerifiableGroupInfo = /* from group */;
let ratchet_tree: RatchetTreeIn = /* from group */;
2

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)?;
3

Complete and finalize

let (mut group, commit, group_info) = commit_builder
    .load_psks(provider.storage())?
    .build(provider.rand(), provider.crypto(), &signer, |_| true)?
    .finalize(provider)?;
4

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