Your user id is not a secret, so knowing it must not grant access to that user's designs. Every SDK request carries two things:
- your app's public SDK key (
tl_pk_…) in thex-tweaklane-keyheader, and - a user token in
Authorization: Bearer <token>, issued by your backend for the signed-in user.
The SDK asks your app's token provider for a token when it needs one, and once more with a forced refresh after an HTTP 401.
Option A: sign tokens on your backend
A user token is an HS256 JWT signed with your secret server key:
| Claim | Value |
|---|---|
iss |
your TweakLane app id (shown in the dashboard) |
sub |
your user id, 1–256 characters |
aud |
"tweaklane" |
iat |
issued at, seconds since the epoch |
exp |
expiry; the lifetime is at most 3600 seconds (configurable per app) |
Node 18+, no dependencies:
import { createHmac } from "node:crypto";
export function tweakLaneToken(userId, { appId, secretKey, ttlSeconds = 900 }) {
const now = Math.floor(Date.now() / 1000);
const encode = (value) => Buffer.from(JSON.stringify(value)).toString("base64url");
const header = encode({ alg: "HS256", typ: "JWT" });
const claims = encode({ iss: appId, sub: userId, aud: "tweaklane", iat: now, exp: now + ttlSeconds });
const signature = createHmac("sha256", secretKey).update(`${header}.${claims}`).digest("base64url");
return `${header}.${claims}.${signature}`;
}
Serve it from an endpoint your app already authenticates with its own session, and return it to the SDK's token provider.
Option B: let TweakLane mint the token
Your backend calls POST /tokens with the secret key:
curl -X POST "{TWEAKLANE_URL}/tokens" \
-H "Authorization: Bearer tl_sk_…" \
-H "Content-Type: application/json" \
-d '{"userId": "user-123", "ttlSeconds": 900}'
{ "token": "eyJhbGciOiJIUzI1NiIs…", "expiresAt": 1794050100 }
expiresAt is the token's exp in seconds since the epoch. ttlSeconds is optional: 60 seconds
up to your app's maximum token lifetime, which is also the default.
Anonymous users
Apps without accounts can let the SDK get a token with only the public key. The SDK sends a random install id it keeps on the device:
curl -X POST "{TWEAKLANE_URL}/tokens/anonymous" \
-H "x-tweaklane-key: tl_pk_…" \
-H "Content-Type: application/json" \
-d '{"installId": "6f1c2a9e-4b7d-4c1e-9a55-0d2f7c3e8b61"}'
The install id is 16–64 characters of A–Z a–z 0–9 -. The token's subject is
anon:<installId> and it lives 900 seconds. Anonymous tokens are off by default; switch them on per
app in the dashboard.
How tokens are checked
The API looks up the app by iss, requires the public key to belong to that app, verifies the
signature with that app's secret (HS256 only; alg: none and other algorithms are refused), and
checks aud, exp, iat (60 s clock skew) and the lifetime cap. The user id comes only from the
verified sub: a request can read and write only that user's data in that app.
Rotating the secret key
Rotating in the dashboard keeps the previous secret valid for a grace period you choose (0–720 hours), so tokens signed with either key are accepted until it ends. The new secret is shown once.
Next: API: auth and tokens.