A plugin authenticates calls to a backend by exchanging its metatell session for
a scoped plugin API token. Use getPluginApiToken() from
@urth/metatell-sdk/auth when calling a registered plugin API whose audience
(aud) is scoped to a specific client. The host SDK performs the exchange via
the broker; the underlying metatell token is never exposed to the plugin.
import { getPluginApiToken } from "@urth/metatell-sdk/auth";
const token = await getPluginApiToken("plugin-foo-api");
await fetch("https://foo.example.com/api/thing", {
headers: { Authorization: `Bearer ${token}` },
});
The host SDK exchanges the metatell token via the broker and caches the result. The underlying metatell token itself is never returned to the plugin, only the short-lived, audience-scoped plugin API token.
clientId is the plugin API client — the token's aud, e.g. "plugin-foo-api".
It is not the broker's confidential client id.
getPluginApiToken() rejects with typed errors so you can branch on the cause.
All are exported from @urth/metatell-sdk/auth:
| Error | Meaning |
|---|---|
InvalidClientIdError |
clientId was empty or not a string. |
NotAuthenticatedError |
The user is not logged in to metatell. |
PluginApiClientNotFoundError |
clientId is not registered (not on the broker allow-list). |
PluginTokenExchangeError |
The exchange failed, or the host bridge is not wired. |
import {
getPluginApiToken,
NotAuthenticatedError,
PluginApiClientNotFoundError,
} from "@urth/metatell-sdk/auth";
try {
const token = await getPluginApiToken("plugin-foo-api");
} catch (e) {
if (e instanceof NotAuthenticatedError) {
// prompt the user to sign in
} else if (e instanceof PluginApiClientNotFoundError) {
// misconfigured client id
} else {
// PluginTokenExchangeError / InvalidClientIdError
}
}
The backend that receives the token must verify it before trusting any claims:
check the signature, issuer, audience, and expiration, and allow only the
RS256 algorithm. Fetch the signing keys from the JWKS endpoint of the metatell
issuer (<issuer>/protocol/openid-connect/certs), and confirm the aud matches
your registered plugin API client id. Do not trust a token decoded in the
browser as authentication, and never embed backend secrets in the plugin.