Skip to content

A NestJS module for Matrix Federation API authentication (sign and verify requests using homeserver signing keys).

License

Notifications You must be signed in to change notification settings

mntu/nestjs-matrix-federation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nestjs-matrix-federation

A NestJS module for Matrix Federation API authentication.
It provides helpers to sign outbound federation requests and verify inbound signatures using Matrix homeserver signing keys.

✨ Features

  • Load homeserver signing key (homeserver.signing.key) from file
  • Generate public/private key pairs for federation
  • signRequest → sign outbound federation requests with Ed25519
  • verifySignature → validate inbound requests against the origin’s published keys
  • MatrixFederationGuard for inbound verification

📦 Installation

npm install nestjs-matrix-federation

⚙️ Setup

1. Prepare your signing key

The signing key file must be in the same format as Synapse:

ed25519 <key_id> <base64_seed>

2. Import the module

import { Module } from '@nestjs/common';
import { MatrixFederationModule } from 'nestjs-matrix-federation';

@Module({
  imports: [
    MatrixFederationModule.forRoot({
      serverName: 'my.example.com',
      signingKeyPath: '/data/homeserver.signing.key',
      dns: {
        override: {
          homeserver: [
            { name: 'my.example.com', value: 'https://override.example.com' }
          ],
        },
      },
    }),
  ],
})
export class AppModule {}

🔑 Usage

Sign an outbound request

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { MatrixFederationService } from 'nestjs-matrix-federation';

@Injectable()
export class ExampleService {
  constructor(
    private readonly http: HttpService,
    private readonly matrix: MatrixFederationService,
  ) {}

  async send() {
    const { auth } = this.matrix.signRequest({
      method: 'PUT',
      uri: '/_matrix/federation/v1/send/12345',
      destination: 'remote.example.com',
      body: { hello: 'world' },
    });

    await this.http.put(
      'https://remote.example.com/_matrix/federation/v1/send/12345',
      { hello: 'world' },
      { headers: { Authorization: auth } },
    ).toPromise();
  }
}

Verify Inbound Request (Manual)

When another homeserver calls your federation API (e.g. /_matrix/federation/v1/send/txn), you need to verify the Authorization header before processing.

import { Controller, Post, Req, Res } from '@nestjs/common';
import { MatrixFederationService } from 'nestjs-matrix-federation';
import { Request, Response } from 'express';

@Controller('_matrix/federation/v1')
export class FederationController {
  constructor(private readonly federation: MatrixFederationService) {}

  @Post('send/:txnId')
  async handleTxn(@Req() req: Request, @Res() res: Response) {
    const authHeader = req.headers['authorization'] as string;

    // Example header:
    // X-Matrix origin=remote.example.org,key="ed25519:a_Kvlj",sig="AbCdEf..."

    const match = authHeader.match(/origin=(.*?),key="(.*?)",sig="(.*?)"/);
    if (!match) {
      return res.status(401).json({ error: 'Missing or invalid auth header' });
    }

    const [, origin, keyId, sigBase64] = match;

    const ok = await this.federation.verifySignature({
      origin,
      keyId,
      sigBase64,
      method: req.method,
      uri: req.originalUrl,
      destination: 'my.example.com',
      body: req.body,
    });

    if (!ok) {
      return res.status(403).json({ error: 'Signature verification failed' });
    }

    // ✅ Request verified, handle transaction
    return res.json({ ok: true });
  }
}

Verify Inbound Request (Guard)

Use the provided MatrixFederationGuard to protect federation endpoints.

import { Controller, Post, UseGuards, Req } from '@nestjs/common';
import { MatrixFederationGuard } from 'nestjs-matrix-federation';
import { Request } from 'express';

@Controller('_matrix/federation/v1')
export class FederationController {
  @UseGuards(MatrixFederationGuard)
  @Post('send/:txnId')
  async handleTxn(@Req() req: Request) {
    // If you reach here the signature is valid
    return { ok: true };
  }
}

🧪 Testing

Run unit tests:

npm test

Unit tests cover:

  • Key loader
  • Signing requests
  • Verifying signatures
  • Middleware behavior

📜 License

MIT

About

A NestJS module for Matrix Federation API authentication (sign and verify requests using homeserver signing keys).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •