Miniapp Identity Token — Validation Guide
Request the token
From the miniapp, call the Application service intent get-identity-token to obtain a signed JWT proving the current user's identity.
Intent reference
| Field | Value |
|---|---|
| Service | Application |
| Action | get-identity-token |
| Availability | Developer |
Parameters: None — the target application is inferred from the calling mini-app.
JWT claims returned: sub = userId, aud = callingApplicationId, iss = platform, exp = 5 min from now.
Usage example
import { ValuApi } from "@arkeytyp/valu-api";
let valuApi = globalThis.valuApi;
if (!valuApi) {
valuApi = globalThis.valuApi = new ValuApi();
}
async function fetchIdentityToken() {
const appService = await valuApi.getApi('Application');
const token = await appService.run('get-identity-token');
// Send the token to your backend with each request
const res = await fetch('https://your-backend.example.com/api/data', {
headers: { Authorization: `Bearer ${token}` },
});
return res.json();
}WARNING
The token is valid for 5 minutes. You can reuse it for multiple requests within that window — just make sure to request a fresh one before it expires.
Fetch the public keys
Your backend fetches the JWKS once and caches it (keys change only on platform restart):
GET https://<platform-host>/.well-known/jwks.json{
"keys": [{
"kty": "RSA",
"use": "sig",
"alg": "RS256",
"kid": "<key-id>",
"n": "...",
"e": "AQAB"
}]
}Validate the token
Match the JWT kid header to the correct key in the JWKS, then verify:
| Check | Expected value |
|---|---|
| Signature algorithm | RS256 |
iss | Platform issuer (e.g. https://api.roomful.net) |
aud | Your miniapp ID |
exp | Must be in the future |
The sub claim contains the verified platform user ID.
Node.js example (using jose)
import { createRemoteJWKSet, jwtVerify } from "jose";
const JWKS = createRemoteJWKSet(
new URL("https://<platform-host>/.well-known/jwks.json")
);
async function verifyIdentityToken(token) {
const { payload } = await jwtVerify(token, JWKS, {
issuer: "https://<platform-host>",
audience: "YOUR_APP_ID",
});
return payload.sub; // platform user ID
}Security notes
DANGER
Never validate tokens client-side; signature verification must happen on your backend.
- Always verify
aud— a token issued for a different miniapp must be rejected. - Cache JWKS with a TTL (e.g. 1 hour) but re-fetch when you encounter an unknown
kid. - Do not accept expired tokens — the 5-minute window is intentional; reject anything with
expin the past.