Developers
Protect an embedded map
Authorize visitors on your backend, exchange a server key for short-lived viewing tokens, and handle renewal and revocation.
Configure access in Maphere
- As a workspace owner/admin, open Share and save the Protected access mode before the first publication of a sensitive map.
- Publish the reviewed map, enable website embeds, and save your exact website origin. A plain iframe cannot authorize a protected map.
- Open Developer access & API keys. Create a named key with only Create viewing tokens (viewer:tokens), and choose its expiry. A viewer-only integration needs no content-field grants.
- Store the one-time secret in your backend’s secret manager. Copy the SDK map ID separately. Never send the mhk_ secret to a browser, URL, analytics tool or public environment variable.
How protected viewing works
Scroll the diagram horizontally to see all participants, or read the steps below.
Read the flow step by step
- Visitor + browser SDK → Your backend: The browser calls your same-origin token endpoint using the visitor’s signed-in session.
- Your backend → Maphere API: After checking visitor and venue permissions, your backend uses its secret API key to request a session for a fixed map and parent origin.
- Maphere API → Your backend: Maphere checks key, map, workspace, embed settings and exact origin, then issues a short-lived token.
- Your backend → Visitor + browser SDK: The backend returns the viewing token and expiry with a no-store response. The secret key never leaves the backend.
- Visitor + browser SDK → Maphere API: The SDK passes the token to the hosted viewer, which uses it for authorized map and image requests.
- Visitor + browser SDK → Your backend: The SDK requests another token before expiry. Your backend must recheck the visitor’s current permission every time.
The diagram combines the browser SDK and hosted iframe as the visitor side. Their messages validate the parent window, exact origins and connection challenge. Tokens remain in memory; do not put them in iframe URLs, browser storage or cookies.
Add your backend token endpoint
import { createMapApi } from "maphere-sdk/server";
// Implement these checks in YOUR application. They are not SDK functions.
import { authorizeMapVisitor } from "./your-auth";
const api = createMapApi({ apiKey: process.env.MAPHERE_API_KEY! });
const mapId = "33333333-3333-4333-8333-333333333333";
const parentOrigin = "https://portal.example.com";
const headers = { "Cache-Control": "private, no-store" };
// Mount at POST /api/map-token on YOUR backend.
export async function POST(request: Request) {
// Must check sign-in, permission for this venue, CSRF and rate limits.
if (!(await authorizeMapVisitor(request, mapId))) {
return Response.json({ error: "Not authorized" }, { status: 403, headers });
}
try {
const session = await api.createViewerSession(mapId, parentOrigin, {
signal: request.signal,
});
return Response.json(session, { headers });
} catch {
return Response.json({ error: "Map access unavailable" }, { status: 503, headers });
}
}The server client can be used from any supported Node.js backend. The POST export illustrates a Next.js route handler; adapt the Request/Response boundary for your framework. Use HTTPS and preserve no-store headers on successes and failures.
Connect the browser callback
Use the map container and status element from Embed with the SDK. The callback runs for the first connection and again on renewal. Pass its AbortSignal through to fetch, and include your application’s required CSRF header.
import { createMap } from "maphere-sdk";
const map = createMap("#map", {
mapId: "33333333-3333-4333-8333-333333333333",
getViewerToken: async ({ signal }) => {
const response = await fetch("/api/map-token", {
method: "POST",
credentials: "same-origin",
cache: "no-store",
signal,
// Add the CSRF header required by your application's backend.
});
if (!response.ok) throw new Error("Map access unavailable");
return response.json(); // Short-lived { token, expiresAt }.
},
});
map.on("error", () => {
document.querySelector("#map-status")!.textContent =
"Map access ended. Sign in and reconnect.";
});
void map.ready.catch(() => map.destroy());
window.addEventListener("pagehide", () => map.destroy(), { once: true });Renewal, revocation and testing
| Event | What happens |
|---|---|
| Normal viewing | A token lasts at most 5 minutes, bounded by key expiry. The SDK requests renewal about 1 minute before expiry. |
| Key revoked or map access changes | Future protected requests fail. The viewer rechecks access every 30 seconds and clears when authorization fails or expires. |
| Network or token endpoint fails | Access is not extended. Show a sign-in/reconnect action; never substitute a server key. |
| A new publication becomes active | Reconnect to load a consistent map and content snapshot. |
| Visitor already copied content | Revocation cannot recall bytes that were already delivered. |
- Test an authorized visitor, an unauthorized signed-in visitor and a signed-out visitor.
- Open the direct viewer, old image URL and a protected resource without a token; none should expose the protected map.
- Test key revocation, expiry, backend denial and offline behavior. Confirm the loaded viewer clears and the host shows a recovery action.
- For routine key rotation, create a replacement, update the backend, verify a fresh connection, then revoke the old key. Existing sessions from the old key will end.