Token verifier
@kittl/sdk-backend helper for verifying short-lived Kittl user JWTs from kittl.auth.getUserToken(). See the SDK backend overview for install and the typical flow.
API
new KittlSDK({ appId, cacheMaxAgeMs?, cacheMaxEntries?, signingKeyCache?, onSigningKeyCacheError?, timeoutMs? }): create a backend SDK instance for your appSigningKeyCache: optional external cache for resolved PEM signing keyskittlBackend.verifyUserToken(token): verify a JWT and return{ sub, aud, iss, iat, exp }TokenInvalidError/TokenInvalidErrorCode: thrown when verification fails
End-to-end flow
- In your app frontend, call
kittl.auth.getUserToken()to get a short-lived JWT for the current Kittl-authenticated user. - Send that token to your backend with the request you want to authorize.
- On your backend, verify the token with
@kittl/sdk-backendbefore handling the request.
Frontend: get a Kittl user token
import { kittl } from '@kittl/sdk';
const tokenResp = await kittl.auth.getUserToken();
if (!tokenResp.isOk) {
// Handle tokenResp.error
return;
}
const { token } = tokenResp.result;
await fetch('https://your-backend.example/api/do-something', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
});
getUserToken() returns a short-lived JWT representing the current Kittl-authenticated user for your app. This is separate from OAuth provider tokens you may retrieve with kittl.auth.getAuthToken().
Backend: verify the Kittl user token
Initialize once (for example at module load time), then verify the token your frontend obtained from getUserToken():
import { KittlSDK, TokenInvalidError } from '@kittl/sdk-backend';
const kittlBackend = new KittlSDK({
appId: process.env.KITTL_APP_ID!,
});
try {
const payload = await kittlBackend.verifyUserToken(token);
console.log(payload.sub);
} catch (error) {
if (error instanceof TokenInvalidError) {
// Return 401 Unauthorized.
}
throw error;
}
appId is used as the JWT audience, so tokens issued for a different app are rejected.
The verified token's sub claim is a pseudonymous per-app user ID.
How verification works
The verifier:
- fetches signing keys from the Kittl API JWKS endpoint for your app
- validates RS256 signatures, issuer, audience, and standard JWT expiry claims
- returns a typed payload with
sub,aud,iss,iat, andexp
Error handling
Verification failures throw TokenInvalidError. Use error.code to distinguish cases such as expired tokens or missing signing keys:
| Code | When |
|---|---|
invalid_options | Missing or invalid verifier options (for example, no appId) |
invalid_token | Token failed signature or claim validation |
missing_key_id | JWT header is missing kid |
signing_key_unavailable | JWKS lookup failed |
token_expired | Token exp is in the past |
token_not_active | Token nbf is in the future |
unexpected_payload | Verified JWT is missing required claims |
Optional tuning
KittlSDK accepts optional cache and timeout settings:
const kittlBackend = new KittlSDK({
appId: process.env.KITTL_APP_ID!,
cacheMaxAgeMs: 60 * 60 * 1000,
cacheMaxEntries: 5,
timeoutMs: 5_000,
});
By default, signing keys are cached in memory per SDK instance for up to
cacheMaxAgeMs (default: 1 hour) and up to cacheMaxEntries keys (default: 5).
Persistent signing key cache
When your runtime does not reuse process memory between requests, provide a persistent
signingKeyCache to reuse keys across restarts and cold starts — for example on edge,
serverless, or other ephemeral backends. The adapter is checked before the SDK's in-memory JWKS cache,
so its get method runs on the token verification path — prefer low-latency storage
and add local memoization if remote I/O per verification would be too expensive.
import { KittlSDK, type SigningKeyCache } from '@kittl/sdk-backend';
const signingKeyCache: SigningKeyCache = {
async get(key) {
return await store.get(key);
},
async set(key, publicKeyPem, { ttlMs }) {
await store.set(key, publicKeyPem, { ttlMs });
},
};
const kittlBackend = new KittlSDK({
appId: process.env.KITTL_APP_ID!,
signingKeyCache,
onSigningKeyCacheError(error, context) {
logger.warn({ error, ...context }, 'Kittl signing key cache error');
},
});
Cache errors are reported through onSigningKeyCacheError and do not fail token
verification; the SDK falls back to its in-memory signing key cache, then to
Kittl's JWKS endpoint when needed.