Skip to main content

Tokens

Looking for the product view?
The Help Center explains this surface as users see it: External links.

Apps use the app_view token type in two distinct ways, and it pays to keep them apart:

KindCreated byStored?Purpose
Runtime view tokensThe platform, automatically, when it serves an app's host pageNo. Stateless JWTs; all claims (appId, username, roles) travel in the token itselfAuthorize the app's own API traffic (proxy calls, handler dispatch, assets) for the duration of a view
External-link tokensA person, via the External Links dialog or this APIYes. A Token row per linkShare an app with people who have no Informer account

GET /api/apps/{id}/tokens lists only the second kind. Runtime tokens never appear in any list because they are never written to the database.

GET /api/apps/{id}/tokens

Get the external-link token rows associated with an app.

Authentication: Required

Permissions Required: None (any user who can read the app)

Path Parameters:

ParameterTypeDescription
idstringApp UUID or natural ID
List an App's tokensGET /api/apps/admin%3Aorder-desk/tokens
Every row here is user-created (External Links or API tokens UI). Runtime app_view tokens are stateless JWTs and never appear in this list.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/tokens"
}
},
"_embedded": {
"inf:app-token": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/tokens/00000000-0000-4000-8000-000000000001"
},
"inf:token-type": {
"href": "https://informer.example.com/api/token-types/app_view"
}
},
"permissions": {
"edit": true,
"delete": true
},
"id": "00000000-0000-4000-8000-000000000001",
"type": "app_view",
"readOnly": true,
"notes": "Quarterly ops review link",
"restrict": null,
"host": null,
"cidr": null,
"data": {
"roles": []
},
"requests": 0,
"blocked": 0,
"lastAccessedAt": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"username": "admin",
"reportId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"datasetId": null,
"appId": "00000000-0000-4000-8000-000000000002",
"assistantId": null,
"oauthClientId": null,
"key": "eyJhbGciOiJIUzI1NiJ9.example-token-1.signature"
}
]
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

Rows are embedded under _embedded["inf:app-token"]. Each row's key is the shareable token string, a JWT signed at response time; it is never stored in the database (this prevents session stealing by reporting on Informer's own tables).

Error Responses:

  • 404 Not Found - App doesn't exist or user lacks access

External-link tokens are created through the general Token API (POST /api/tokens), not through an app-specific endpoint. This is exactly the request the External Links dialog sends:

Create an external-link tokenPOST /api/tokens
This is the payload the External Links dialog sends. appId must be the app UUID, not the natural id. The key is a signed JWT computed at response time, never stored.
Request body
{
"type": "app_view",
"appId": "00000000-0000-4000-8000-000000000001",
"readOnly": true,
"notes": "Quarterly ops review link",
"data": {
"roles": []
}
}
Response · 201
{
"_links": {
"self": {
"href": "https://informer.example.com/api/tokens/00000000-0000-4000-8000-000000000002"
},
"inf:token-type": {
"href": "https://informer.example.com/api/token-types/app_view"
}
},
"resource": "Order Desk",
"permissions": {
"edit": true,
"delete": true
},
"id": "00000000-0000-4000-8000-000000000002",
"type": "app_view",
"readOnly": true,
"notes": "Quarterly ops review link",
"restrict": null,
"host": null,
"cidr": null,
"data": {
"roles": []
},
"requests": 0,
"blocked": 0,
"lastAccessedAt": null,
"expiresAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"username": "admin",
"reportId": null,
"queryId": null,
"visualId": null,
"datasourceId": null,
"datasetId": null,
"appId": "00000000-0000-4000-8000-000000000001",
"assistantId": null,
"oauthClientId": null,
"user": {
"permissions": {
"changeDomain": true,
"changeProfile": true,
"changePassword": false,
"delete": true,
"edit": true,
"reassign": true,
"superuser": true,
"enable": true,
"changeTheme": true,
"lock": true,
"setGlobalPermissions": true,
"manageLogin": false
},
"displayName": "acme Administrator",
"email": null
},
"assistant": null,
"oauthClient": null,
"key": "eyJhbGciOiJIUzI1NiJ9.example-token-1.signature",
"_embedded": {
"inf:app": {
"_links": {
"self": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001"
},
"inf:owner": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/owner"
},
"inf:draft": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/draft"
},
"inf:app-shares": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/shares"
},
"inf:app-tags": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/tags"
},
"inf:favorite": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/favorite"
},
"inf:app-tag": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/tags/{tagId}",
"templated": true
},
"inf:export-bundle": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/_export"
},
"inf:cloud-publish": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/_cloud-publish"
},
"inf:copy": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/_copy"
},
"inf:print": [
{
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/_print"
},
{
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/_print",
"title": "Print to PDF"
}
],
"inf:migrate": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/_migrate"
},
"inf:deploy": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/_deploy"
},
"inf:app-tokens": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/tokens"
},
"inf:app-roles": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/roles"
},
"inf:app-dependencies": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/dependencies"
},
"inf:app-dependency": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/dependencies/{name}",
"templated": true
},
"inf:app-environment": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/environment"
},
"inf:app-environment-var": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/environment/{key}",
"templated": true
},
"inf:app-suggest-icon": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/_suggest-icon"
},
"inf:app-modernize-manifest": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/_modernize-manifest"
},
"inf:app-draft-diff": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/draft/_diff"
},
"edit": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/_edit"
},
"inf:app-share": {
"href": "https://informer.example.com/api/apps/00000000-0000-4000-8000-000000000001/shares/{principalId}",
"templated": true
},
"inf:entrypoint": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/view/",
"title": "index.html"
},
"inf:library": {
"href": "https://informer.example.com/api/libraries/00000000-0000-4000-8000-000000000003",
"title": "App Files"
},
"inf:library-contents": {
"href": "https://informer.example.com/api/libraries/00000000-0000-4000-8000-000000000003/contents/index.html",
"title": "Raw Contents"
},
"share": {
"href": "https://informer.example.com/api/apps/admin%3Aorder-desk/view/?token=%7Btoken%7D",
"title": "Share Page"
}
},
"naturalId": "admin:order-desk",
"isManaged": false,
"permissions": {
"assignTags": true,
"bind": true,
"changeOwner": true,
"copy": true,
"delete": true,
"edit": true,
"manage": true,
"purge": true,
"restore": true,
"run": true,
"share": true,
"switchRoles": true,
"write": true
},
"id": "00000000-0000-4000-8000-000000000001",
"type": "report",
"name": "Order Desk",
"tenant": "acme",
"ownerId": "admin",
"slug": "order-desk",
"description": null,
"defn": {
"entryPoint": "index.html"
},
"settings": {
"sandbox": true,
"passDatasets": true
},
"origin": "ui",
"source": null,
"sourceId": null,
"shared": false,
"defnUpdatedAt": null,
"libraryId": "00000000-0000-4000-8000-000000000003",
"webhookSecret": "encrypted:iv:0000000000000000",
"dbRolePassword": null,
"deletedAt": null,
"editingId": null,
"deployedAt": null,
"editingSession": null,
"editingHeartbeatAt": null,
"editingLockedBy": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"folderId": null,
"contentModifiedAt": "2026-01-15T16:20:00.000Z"
}
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

Payload Fields:

FieldTypeDescription
typestringMust be "app_view" (underscore, not a dash)
appIdstringApp UUID. Natural ids are rejected (appId is a UUID foreign key); resolve the app first if you only have ownerId:slug.
readOnlybooleanThe External Links dialog always sends true, restricting the link to GETs and routes explicitly marked read-only safe
notesstringFree text for tracking where the link is used
restrictstringOptional network restriction: host or cidr
hoststringHostname or IP, when restrict: "host"
cidrstringIP range (e.g. 192.168.1.0/24), when restrict: "cidr"
data.rolesarrayApp role ids (from the manifest's roles:) granted to visitors using this link

Permissions Required: tokens:create

The response is 201 Created. The key in the response is the token string to embed in the share URL.

The share URL

https://<your-informer>/api/apps/{id}/view?token=<key>

The token travels as a ?token= query parameter on the view URL; visitors need no Informer account and see only the app.

Editing and revoking

  • PUT /api/tokens/{tokenId} updates notes, network restrictions, and roles (the External Links dialog's edit mode).
  • DELETE /api/tokens/{tokenId} revokes the link immediately.

What an app_view token can reach

Authorization is a closed allowlist of route ids, checked on every request. A token (runtime or external-link) authorizes only the app-render surfaces:

  • GET /api/apps/{id}/view/{path*} - the app's host page and SPA routes
  • GET /api/apps/{id}/launch/{path*} - the standalone/home-screen entry
  • GET /api/apps/{id}/launch/icon-180.png - the iOS tile icon
  • /api/apps/{id}/view/api/{path*} - the data-access proxy (all methods, subject to the app's declared API whitelist)
  • /api/apps/{id}/view/_/{path*} - the app's own server-route handlers
  • GET /api/apps/{id}/view/-/{path*} - static assets

Everything else returns 401, even with a valid token for that app: the app detail GET, _export, _copy, contents, and every other app-scoped route are outside the allowlist. The token must also match the app in the URL (appId or natural id), so a token for one app can never be replayed against another.

Read-only enforcement: when readOnly: true (every external link), the session additionally rejects any request that is not a GET or not explicitly marked read-only safe. Runtime view tokens are minted with readOnly: false because apps legitimately POST through the proxy; their gating comes from the route allowlist and the app's API whitelist.


Security Considerations

  • Treat the key as a password. Anyone holding the URL has the link's access until the row is deleted.
  • Tokens are visible to anyone who can read the app via the list route, including each link's key.
  • Scope with roles. Grant link visitors only the app roles they need; an empty data.roles array grants none.
  • Pin the network when you can. restrict: "cidr" keeps a link from working outside your office or VPN range.
  • The data whitelist still applies. Proxy calls through /view/api/ are validated against the app's declared API access, regardless of who is asking.
  • GET /api/apps/{id}/webhook-tokens - revocable tokens for inbound webhooks (a separate token type)
  • GET /api/tokens / GET /api/tokens/{id} - the general Token API
  • GET /api/apps/{id}/data-access - the whitelist that bounds proxy calls