Build a Sign-in Mini App Not yet released
The path from nothing to a Mini App that signs a person in with their Micromeet account and then calls Micromeet for them from its own backend. Every function is described in Sign-in, packaging in Build and Sign, and every package rule in Package Spec.
The whole flow
Who does what, from the first build to a person opening the Mini App:
Cowork checks the signature on every open, and every file whenever the page reads it; a changed file closes the Mini App.
Signing in, after the person clicks your button:
The page never sees a password, a token or the client secret. The steps below build each part.
1. Ask Micromeet to register the Mini App
There is no self-registration. Send Micromeet:
| What | Example |
|---|---|
| AppID: a lower-case reverse domain | ai.example.app |
| Name (English; Chinese optional) and developer | Example · Example Ltd |
| Scopes the Mini App needs | profile:read |
| Regions of the people who will sign in (SG, HK, ID) | HK |
| Your backend's origin | https://api.example.com |
For each region you get a client secret, shown once: keep it in the backend's secret store. For each origin you get a verification file (step 2).
2. Prove you own the backend's domain
Serve the file at https://api.example.com/micromeet-miniapp-<16 characters>.txt over HTTPS, with status 200 and no redirect, and leave it there; Micromeet fetches it to verify the domain. During development the backend can run on http://localhost:<port> or http://127.0.0.1:<port>, which needs no file in the regions where Micromeet allows it. See Server domains.
3. Write the page
Install @micromeet-ai/miniapp-sdk (see Build and Sign), then:
import { maestroSdk } from '@micromeet-ai/miniapp-sdk';
const BACKEND = 'https://api.example.com'; // a verified server domain
export async function signIn() {
const sdk = maestroSdk(); // null outside Cowork
if (!sdk?.auth) return { error: 'open_in_cowork' };
const login = await sdk.auth.login({ scopes: ['profile:read'] });
if (!login.ok) return { error: login.error };
const response = await fetch(`${BACKEND}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code: login.code, region: login.region })
});
return response.json(); // { session, name }: send session with later requests
}- Call
auth.login()when the person clicks: Cowork shows its card only on the tab the person is looking at. auth.status()says whether the package is signed and whether someone is signed in to Cowork; use it to show or hide the button.- Put every script in a file: inline
<script>does not run.
4. Write the backend
A minimal Node.js backend:
import { createServer } from 'node:http';
import { randomUUID } from 'node:crypto';
import { createMiniappAuthClient, MiniappAuthError } from '@micromeet-ai/miniapp-sdk/server';
const APP_ID = 'ai.example.app';
const PAGE = `miniapp://${APP_ID}`; // the page's origin
// One client per region, each with that region's secret.
const clients = { HK: createMiniappAuthClient({ appId: APP_ID, clientSecret: process.env.MINIAPP_SECRET_HK }) };
const sessions = new Map(); // keep these in your database
const reply = (res, status, body) => {
res.writeHead(status, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': PAGE, Vary: 'Origin' });
res.end(JSON.stringify(body));
};
createServer((req, res) => {
if (req.method === 'OPTIONS') {
res.writeHead(204, { 'Access-Control-Allow-Origin': PAGE, 'Access-Control-Allow-Methods': 'POST', 'Access-Control-Allow-Headers': 'Content-Type, Authorization' });
return res.end();
}
if (req.method !== 'POST' || req.url !== '/login') return reply(res, 404, { error: 'not_found' });
let raw = '';
req.on('data', (part) => (raw += part));
req.on('end', async () => {
try {
const { code, region } = JSON.parse(raw);
const auth = clients[region];
if (!auth) return reply(res, 400, { error: 'region_not_supported' });
const tokens = await auth.exchangeCode({ code, region });
const session = randomUUID();
sessions.set(session, { ref: tokens.user.ref, region, refreshToken: tokens.refreshToken });
reply(res, 200, { session, name: tokens.user.name });
} catch (error) {
reply(res, 400, { error: error instanceof MiniappAuthError ? error.code : 'bad_request' });
}
});
}).listen(8787);- Answer
Access-Control-Allow-Origin: miniapp://<appId>: that is the page's origin, and without it the request fails in the page before it reaches your code. - Key your users by
user.ref, keep the refresh token, and get new tokens withrefreshwhen you call Micromeet later. - The page gets only your own session; Micromeet's tokens stay in the backend.
- Run it on your verified server domain; during development, on localhost. A backend in another language makes the same calls (see Sign-in, HTTP calls).
5. Build, sign and install
- Add
domains: ['https://api.example.com']to the Vite plugin and runvite build(see Build and Sign). - Run
micromeet-miniapp verify miniapp-package, then hand the package to Micromeet, which registers and signs this version in each region and returns the signedmanifest.json: put it back in the package. - Run
micromeet-miniapp verify miniapp-package --signed, thenmicromeet-miniapp zip miniapp-package. - In Cowork, ask the agent to install the zip, open the Mini App and sign in.
The released Cowork opens only versions Micromeet's production signed; there is no unsigned development mode.
6. Develop and test
- Screens and logic that do not need sign-in:
vite devin a browser. TheremaestroSdk()isnull, so show a short note instead of the button. - Only the page's files are signed: a change to the backend needs no new version. Keep the page simple and the logic in the backend.
- A change to any page file or to
domainsneeds a newversion, registered, signed and installed again. - Testing sign-in end to end needs a signed version and a Cowork signed in to an account of a region where the Mini App is registered.
- A development version may list only a localhost domain. Leave localhost out of a release version: a region that does not allow localhost refuses its sign-in with
no_server_domain.
If something goes wrong
| Where | You see | Cause and fix |
|---|---|---|
| Cowork | The Mini App is not certified and does not open | The package is not signed, was signed by another Micromeet environment, or a file changed after signing: install the signed zip |
| Page | app_not_available | The AppID is not registered in the person's region, or it is disabled |
| Page | version_not_available | This version is not registered in that region, or it is disabled |
| Page | no_server_domain | The version has no verified server domain in that region, or the verification file is gone |
| Page | scope_denied | The page asked for a scope Micromeet did not allow this Mini App |
| Page | fetch fails with a CORS error | The backend does not answer Access-Control-Allow-Origin: miniapp://<appId> |
| Backend | invalid_client | The secret is wrong for this region, or it was replaced |
| Backend | invalid_grant | The code was used already, is older than 5 minutes, or is for another AppID |
Related
- Sign-in Every sign-in function, the backend helper and its errors
- Build and Sign Make the package and have Micromeet sign it
- Package Spec Every rule a package must meet