Skip to content

Developing Frontends for Extensions

freisenhauer edited this page May 22, 2025 · 15 revisions

Warning

This documentation is no longer up to date and won't be maintained anymore. For an up to date version, please see our Developer Portal.

Frontend Variants in mStudio

In mStudio, there are two main ways to implement a frontend for your extensions:

External Frontend

  • How it works: Opens in a new tab or window.
  • Technology and design: You have complete freedom to choose any technology stack and design your extension however you like.
  • When to use it: Ideal if you need full control over your extension’s design and behavior.

External frontends operate independently from mStudio by calling an external service. This approach is perfect if you don't need deep integration with the mStudio environment.

Embedded Frontend via Frontend Fragments

  • How it works: Your extension is embedded directly inside mStudio using an iFrame.
  • Technology and design: You build using the same UI components as mStudio, creating a seamless user experience.
  • When to use it: Best suited when you want tight integration into mStudio while maintaining a consistent look and feel.

Mehr Details zu dieser Variante findest du im Abschnitt Benefits of Embedded Frontends.

Benefits of Embedded Frontends

  • Provides a consistent and user-friendly interface by reusing mStudio’s UI components.
  • Leverages predefined "attachment points" (called "Frontend Fragments") to integrate your extension into the mStudio interface.
  • Creates a seamless experience for users without switching between different systems.

Building a New Extension with Frontend Fragments

Follow these steps to build an extension that uses Frontend Fragments:

1. Select and Configure a Fragment

2. Set Up Local Development

  • During development, you can point your fragment’s URL to http://localhost:3000. This lets you build and test your extension locally before deploying it live.
  • You can also create a hidden copy of your extension for local development.
  • A more streamlined development environment for Frontend Fragments is coming soon to make the process even easier.

3. Build Your Frontend

  • Use @mittwald/flow-remote-react-components to develop your frontend.
  • See the next section for details

Build your Frontend with Flow

Introduction and Notes

Embedded frontends use a remote architecture that mirrors web components rendered inside an iFrame as React components into mStudio. Therefore, development cannot (yet) happen entirely locally — you must use an mStudio instance with an installed extension as the entry point.

Currently, it is recommended to build your frontend with React, because ready-to-use remote components for Flow are available (Flow Components Documentation). You are free to choose any framework you like, such as Vite, Next.js, or others.

Your frontend should be running on http://localhost:3000, and an appropriate frontend fragment should be configured (see Setting up Fragments).

Hello World Example

First, install Flow Remote Components:

npm install @mittwald/flow-remote-react-components

Example React component:

import {
  Alert,
  CodeBlock,
  Content,
  Heading,
} from "@mittwald/flow-remote-react-components";
import RemoteRoot from "@mittwald/flow-remote-react-components/RemoteRoot";
import { useConfig } from "@mittwald/ext-bridge/react";

function SessionInfo() {
  const config = useConfig();
  return <InlineCode>{config.sessionId}</InlineCode>;
}

export default function Demo() {
  return (
    <RemoteRoot>
      <Alert>
        <Heading>Hello World!</Heading>
        <Content>
          This is my first extension: <SessionInfo />
        </Content>
      </Alert>
    </RemoteRoot>
  );
}

Ingredients used in the Example

<RemoteRoot>

This component is the root of your extension. React components placed under <RemoteRoot> are synchronized into the Fragment in mStudio. It should only appear once in your app and the components you may use are limited. See the caveats about Limited Components. When the <RemoteComponent> is mounted, you have access to the Ext Bridge.

Flow Remote Components

It is important to use the remote version of Flow components. Instead of @mittwald/flow-react-components, you must import from @mittwald/flow-remote-react-components.

You can find a full documentation of available components here.

useConfig()

Components below the <RemoteRoot> do have access to the Ext Bridge configuration by using the useConfig() hook. The config holds some relevant information, like the userId, projectId or sessionId.

Test your extension

In order to test if the integration is working correctly, you should first start your dev server. Then install the extension via the mStudio and navigate to the extension page by clicking the menu item of the project or customer main navigation on the left. You should now see the "Hello World" example 🎉

Caveats using Flow Remote Components

There are some limitations, you should know when developing with remote components.

Limited Components

Under the <RemoteRoot> component it is only allowed to render the following components: components except:

You can also build up your own components, but finally they must use the components listed above.

If you use other components you will see an error in the console, telling what component is not supported.

Limited Custom Styling

The following props will not be applied in the mStudio view. Therefore it is not possible, to ship your own CSS or styles.

  • className
  • style

Event Data

Most of the event data will be accessible by your event handlers, as you would expect when developing with local React. There are some edge cases where the event data may be incomplete. This is because events will be first serialized and then "transported back" to your extension. This is especially limits the use of native browser APIs. If you need support here, please file an issue.

Customize the mStudio page header for your extension

If you need to customize the mStudio page header (title, breadcrumb, actions), you can use the @mittwald/mstudio-ext-react-components package.

Connecting Your Own Backend

When Do You Need a Backend?

Adding your own backend makes sense if you:

  • Want to persist data (e.g., user settings, logs, or other stored information),
  • Need to interact with the mittwald API (e.g., fetch project or customer data),
  • Require server-side logic or external integrations (e.g., data processing, providing custom APIs).

Having a backend gives you full flexibility to define server-side processes, manage sessions, or build complex business logic.

Weitere Details dazu, wie du eine sichere Kommunikation zwischen Frontend und Backend umsetzt, findest du im Abschnitt Session Handling and Configuration Values via Ext Bridge.

Session Handling and Configuration Values via Ext Bridge

Because embedded frontends run inside an iFrame, browser restrictions can make cookie handling difficult.

To solve this, you can use @mittwald/ext-bridge to securely share a session token between mStudio, your frontend, and your backend — keeping the session intact. Your backend can then verify the session token to authenticate requests.

Additionally, the Ext Bridge allows you to retrieve parameters like userId or projectId. See getConfig().

Installation

npm add @mittwald/ext-bridge

How Session Handling Works

  1. Your frontend creates a session token before every backend request. Note: Session tokens expire quickly — generate a fresh token for each request.
  2. Your backend verifies the token.
  3. Your backend (optionally) uses information like userId for authentication.
  4. (Optional) Your backend creates an access token to interact with the mittwald API.

Difference Between Session Token and Access Token

  • A Session Token is generated by your frontend using @mittwald/ext-bridge.
    It is short-lived and used to authenticate communication between your frontend and your own backend.
    The session token proves that a request originates from a logged-in user inside mStudio.

  • An Access Token, on the other hand, is generated server-side by your backend.
    It uses the session token and your extension’s secret to create a token that allows access to the mittwald API.
    Access tokens are needed when your backend wants to fetch or modify project, customer, or other data directly from mittwald services.

Important: Always create a fresh access token on demand. Never cache or reuse access tokens.

Frontend Implementation

getSessionToken()

Use getSessionToken() to generate a session token.

Important:

  • Server-Side Rendering (SSR) is not supported — the function must be called client-side.
  • The method is available only after the <RemoteRoot> component has been rendered.
  • Therefore, do not call the method during initial rendering (e.g., inside useEffect), but only right before a backend request.

Example:

import { getSessionToken } from "@mittwald/ext-bridge/browser";

const token = await getSessionToken();

Example: Axios Interceptors

Since tokens are short-lived, it’s recommended to use an HTTP client middleware or interceptor to attach a fresh token to each request automatically.

Example using Axios:

import { getSessionToken } from "@mittwald/ext-bridge/browser";

axios.interceptors.request.use(async (request) => {
  const token = await getSessionToken();
  request.headers.set("x-session-token", token);
  return request;
});

getConfig() / useConfig() (React)

Through these methods, you can access parameters useful for your frontend implementation. The return type is:

type ExtBridgeConfig = {
  sessionId: string;
  userId: string;
  extensionId: string;
  extensionInstanceId: string;
  appInstallationId?: string;
  projectId?: string;
  customerId?: string;
};

If you are using React, you can use the useConfig() hook.

Backend Implementation

verify()

Use the verify() method to validate a session token. If successful, it confirms that the request was made by a logged-in user from mStudio; otherwise, an error is thrown.

Important: Always create a fresh access token on demand. Never cache or reuse access tokens.

Session Token Payload

The verify() method returns a verified and decoded session token with the following structure:

type SessionTokenPayload = {
  sessionId: string;
  userId: string;
  extensionId: string;
  extensionInstanceId: string;
  contextId: string;
  context: "project" | "organization";
  scopes: string[];
};

Example: Express Middleware

Example of an Express middleware that verifies the session token and attaches the payload to the request object:

import { verify } from "@mittwald/ext-bridge";

app.use((req, res, next) => {
  const token = req.headers["x-session-token"];
  if (!token) return next("router");

  verify(token)
    .then((session) => {
      req.sessionToken = session;
      next();
    })
    .catch(() => res.sendStatus(401));
});

Getting an Access Token to Access the mittwald API

You can also use the session token to get an access token to communicate with the mittwald API.

This operation is secured by your global extension secret. You can create one by using the API route https://api.mittwald.de/v2/contributors/{contributorId}/extensions/{extensionId}/extension-instances/{extensionInstanceId}/secret as documented here. If you got the extension secret make it securely accessible by your backend.

Note: Do not cache nor store access token – always get a new one.

Now you can use the getAccessToken method as follows:

import { getAccessToken } from "@mittwald/ext-bridge/node";

const accessToken = await getAccessToken(
  sessionTokenFromRequest,
  process.env.MY_EXT_SECRET
);

const projectsResponse = await fetch("https://api.mittwald.de/v2/projects", {
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

Available Frontend Fragments

Fragment Path Description Additional Properties
/projects/project/menu/section/extensions/item Menu entry in the project overview projectId
/projects/project/apps/detail/menu-top/item Tab in an app's detail view projectId, appId
/customers/customer/menu/section/extensions/item Menu entry in an organization customerId

See the section Building a New Extension with Frontend Fragments for how to use these fragments in your extension.

Storing Frontend Fragments in Your Extension

To register your frontend fragments, call the API:

PATCH https://api.mittwald.de/v2/contributors/{contributorId}/extensions/{extensionId}

Example Configuration

{
  "/projects/project/menu/section/extensions/item": {
    "url": "https://my-extension.com/project/:projectId",
    "additionalProperties": {
      "icon": "<svg>...</svg>",
      "title": "{\"de\": \"Meine Extension\"}"
    }
  }
}

Under additionalProperties you can define the following:

  • custom icon
  • translated title: Must be an escaped valid JSON string with object format { [languageKey: string]: string }. The following language keys are supported: de.