SubjectClient & Auth
The core package has no React or Vue dependency and can be used standalone:
import { createSubjectTokenProvider, SubjectClient, createChartModel, createTableController,} from '@meterry/component'Application token endpoint
Section titled “Application token endpoint”Configure React’s MeterClientProvider or Vue’s ancestor provideMeterClient with your application route, e.g. /api/meter/subject-token. The helper createSubjectTokenGetter(endpoint, options?) performs a GET, forwards signal, uses credentials: 'include' unless configured otherwise, and returns the grant. Provider options.fetch handles both the token route and Subject API requests. Existing client / getJwt integrations remain supported; precedence is client → getJwt → tokenEndpoint.
The route is implemented by your backend, not by the component or the Meter Subject grant API. Return a grant with access_token plus expiry metadata. See Getting Started for complete examples.
Creating a client
Section titled “Creating a client”Besides passing getJwt directly, the recommended approach is to explicitly create and reuse a SubjectTokenProvider:
const tokenProvider = createSubjectTokenProvider(getSubjectToken)const client = new SubjectClient(tokenProvider, { baseUrl: 'https://api.meterry.com', credentials: 'include',})The signature of getJwt / getSubjectToken is ({ signal }: { signal?: AbortSignal }) => Promise<SubjectTokenGrant>. It should call your backend, which issues a short-lived Subject Token based on the login session.
Token single-flight
Section titled “Token single-flight”A given SubjectTokenProvider keeps at most one JWT request in flight; other components or clients await the same Promise. 401 refreshes use the same single-flight logic, and each API request retries at most once.
Token persistence
Section titled “Token persistence”By default the provider persists Subject Tokens carrying expires_in or expires_at to the browser’s localStorage, under the default key meter:subject-token. You can override the key or disable persistence entirely:
const tokenProvider = createSubjectTokenProvider(getSubjectToken, { tokenStorageKey: `meter:${tenantId}:${userId}`, // tokenStorage: null, // in-memory cache only})Multi-user, multi-tenant, or multi-environment apps should give each auth scope its own tokenStorageKey. In compatibility mode with tokenScope, if no explicit tokenStorageKey is passed the library automatically uses the default key suffixed with the scope. Call clearToken() or clearSharedSubjectToken(scopeKey) on logout or account switching.
You can also share a single provider across components via getSharedSubjectTokenProvider(scope, getJwt, options) (this is what the tokenScope prop of the React/Vue components uses internally).
Query cache on logout / subject changes
Section titled “Query cache on logout / subject changes”For automatic charts, client.clearToken() also invalidates that client’s completed chart cache. Stop/unmount active query components and create an authentication-scoped client before rendering another user/tenant. If an external provider changes identity without clearToken(), explicitly call clearUsageChartCache(client) and remount/refetch active charts; clearing shared token storage alone does not invalidate settled chart results. Automatic table cursor caches are controller-owned and must also be disposed/remounted on an auth-scope change. Do not share one client across simultaneous auth scopes.
Wrapped endpoints
Section titled “Wrapped endpoints”POST /v1/subject/usage/queryPOST /v1/subject/analysis/queryGET /v1/subject/usage/events/detailsGET /v1/subject/realtime/balance
Arbitrary endpoints: client.request()
Section titled “Arbitrary endpoints: client.request()”Beyond the wrapped methods, client.request(path, init) calls any endpoint directly (including endpoints added later), reusing all the token injection, 401 refresh, and retry logic:
const result = await client.request('/v1/subject/usage/export', { method: 'POST', body: JSON.stringify({ format: 'csv' }),})Custom fetch
Section titled “Custom fetch”MeterClientOptions accepts a fetch to replace the default implementation — commonly used for tests and mocks:
const client = new SubjectClient(tokenProvider, { fetch: mockMeterFetch, // (input, init) => Promise<Response>})The interactive previews in this documentation also use a custom fetch adapter with synthetic fixtures. Requests stay entirely inside that adapter; preview tokens are kept in memory with tokenStorage: null, and no production API or browser session credentials are used.
Error handling
Section titled “Error handling”On failure the client throws MeterApiError; isUnauthorizedError(error) tells you whether it was a 401:
import { MeterApiError, isUnauthorizedError } from '@meterry/component'
try { const data = await client.analysisQuery(request)} catch (error) { if (isUnauthorizedError(error)) { // still 401 after token refresh and retry — usually means re-login }}Security model
Section titled “Security model”The browser still must never hold the tenant API key:
Browser ──session──▶ your backend ──tenant API Key──▶ Meter platform │ │ └── short-lived Subject Token ──────────▶ Meter Subject APIgetJwt should call your backend, which issues a short-lived Subject Token based on the login session.
For the backend grant flow and Subject API contracts, see Subject Token Frontend Integration.