Integrate with Shell ~20 min
What Shell expects
Every remote service must expose a ShellEntry component via Module Federation:
typescript
// Your service's src/ShellEntry.tsx
import { BrowserRouter } from 'react-router-dom';
import App from './App';
export default function ShellEntry() {
return (
<BrowserRouter basename="/hrm">
<App />
</BrowserRouter>
);
}1. Configure Module Federation
typescript
// vite.config.ts (remote service)
import federation from '@module-federation/vite';
export default defineConfig({
plugins: [
react(),
federation({
name: 'hrm',
filename: 'hrm-microfrontend.js',
exposes: {
'./ShellEntry': './src/ShellEntry',
},
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true },
'react-router-dom': { singleton: true },
},
}),
],
build: { target: 'esnext' },
});Shared dependencies must be singletons
react, react-dom, and react-router-dom must be declared as singletons. Multiple instances of React in one page will cause hook errors.
2. Listen for auth tokens
Shell UI broadcasts tokens to all remotes via BroadcastChannel:
typescript
// src/auth/token-listener.ts
const channel = new BroadcastChannel('veni-auth');
channel.onmessage = (event) => {
if (event.data?.type === 'TOKEN_UPDATE') {
const { shellToken, keycloakToken } = event.data;
// Store tokens for use in API calls
localStorage.setItem('shell_token', shellToken);
localStorage.setItem('keycloak_token', keycloakToken);
}
};Initialize this listener early in your app (e.g. in main.tsx).
3. Exchange token for service JWT
Use the Keycloak token to get a service-scoped JWT from Shell API:
typescript
const response = await fetch(`${SHELL_API_URL}/api/auth/exchange-keycloak`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: localStorage.getItem('keycloak_token'),
}),
});
const { data } = await response.json();
// data.accessToken = your service JWTUse data.accessToken as the Bearer token for all calls to your own service API.
4. Register the service
Register with Shell so it appears in the dashboard:
bash
curl -X POST http://localhost:3000/api/admin/apps \
-H "Authorization: Bearer <shell-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "HRM",
"slug": "hrm",
"entryUrl": "http://localhost:3004/hrm-microfrontend.js",
"type": "SERVICE",
"status": "AVAILABLE"
}'5. Verify
- Open Shell UI at
http://localhost:5173 - Your service card should appear on the dashboard
- Clicking it loads your
ShellEntrycomponent inside the Shell frame