Prism/developer documentation/Internal API

Internal API

How the web app talks to Prism's API, who a request acts as, and how permissions are checked.

Prism runs two servers. The web server on port 3000 serves the store, the dashboard and sign-in. The API on port 3001 holds every route, including your module's. The web server never touches module data directly. It calls the API for everything.

Requests From the Web App

When the web server calls the API it sends Prism's internal secret plus headers that say who is signed in:

HeaderWhat it carries
Authorization: Bearer <secret>Prism's internal secret from config.json.
x-actor-kindstaff or customer.
x-actor-id, x-actor-name, x-actor-emailThe user.
x-actor-permissionsTheir permissions as a JSON array.
x-actor-discordTheir Discord ID, if linked.
x-actor-ipTheir real IP address.

The API trusts these headers only alongside the secret. Keep the secret private, since anything holding it can act as any user.

This happens in four places:

WherePath
Your page's load()client.send("GET", "/api/modules/<module>/<path>")
Resource pages and your own viewsrequest(module, path), which goes through /api/m/<module>/<path> on the web port
The store/api/v1/ on the web port, forwarded to the API as is
Prism's own pagesBuilt-in routes such as /api/settings and /api/audit

In each case the request reaches your route as that user, so you never handle sessions yourself.

Actors

Every request gets an actor on request.actor:

KindFrom
systemThe secret with no actor headers, such as Prism's own calls. Has every permission.
staffA signed-in team member.
customerA signed-in user with no role.
tokenAn API token from the API Tokens page. Its permissions are the token's scopes.
publicNobody, on a route with access: "public". Has no permissions.

A private route with no valid secret or token answers 401. A token that does not match is written to the audit log.

Checking Permissions

Routes check permissions for you through their permissions option. To check by hand:

if (!this.prism.api.allowed(request.actor, "products.edit")) this.fail(403, this.prism.modules.lang.phrase("example", "messages", "denied"));
Actor hasPasses
*Everything.
products.editproducts.edit.
products.*Any products. permission.
products.manageAny products. permission, for staff.

customer is a special permission that only customers and the system pass. Public actors fail every check except an empty one.

Request Helpers

HelperWhat it does
this.prism.api.allowed(actor, permission)The check above.
this.prism.api.ip(request)The caller's IP. Reads x-actor-ip from the web server, then cf-connecting-ip, then x-forwarded-for.
this.prism.api.address()The public API address from API URL, or http://localhost:3001.
this.prism.web.address()The public site address from Web URL, or http://localhost:3000. Use it for links you give out.

Built-in Routes

These belong to Prism rather than a module. They all need the secret except the first three.

RouteWhat it does
GET /api/statusVersion, whether Prism is running and configured, database and module state.
GET /api/health200 when Prism is running with the database up and no failed modules, otherwise 503.
GET /api/v1/public-keyThe Ed25519 public key used to sign responses.
GET /api/permissionsEvery permission, from Prism and each module.
GET /api/modules, POST /api/modules/toggleList modules and turn them on or off.
GET /api/pagesEvery module page.
GET /api/modules/configs, POST /api/modules/configRead and save config groups.
GET /api/locales, GET /api/modules/dictionaryLanguages and the merged web dictionary.
GET /api/modules/langs, POST /api/modules/langRead and save lang text.
POST /api/translateTranslate text for the Lang page.
GET /api/settings, POST /api/settingsPrism's settings, with secrets hidden.
POST /api/settings/reload, POST /api/restartReload settings from the database, or restart Prism.
POST /api/signing/rotateMake a new response signing key.
GET /api/config, POST /api/configServer ports and URLs.
GET /api/tokens, POST /api/tokens, DELETE /api/tokens/:idAPI tokens.
GET /api/auditThe audit log.
GET /api/logsRecent console lines.

Your module's routes live under /api/modules/<module>, or at their own path when they set absolute: true. See Routes.