Forge.Core Docs
Launch Dashboard

Resource Tokens

Short-lived, HMAC-signed tokens scoped to a single resource — the signed-URL primitive. An app backend asks Forge Core to issue a token for one resource, and anyone holding that token can ask Forge Core to decode it.

What this is (and isn't)

Forge doesn't know or care what a "resource" is — it just signs and verifies a small claim: this resourceId, this action, until this expiry. Serving the actual file or data once a token checks out is entirely up to your app (fetch from storage, proxy a file, redirect to a CDN URL, and so on).

Token format

A token looks like <base64url(payload)>.<base64url(HMAC-SHA256 signature)>. It's signed with a dedicated server secret (FORGE_RESOURCE_TOKEN_SECRET), kept separate from the Better Auth secret and the internal FORGE_CORE_SECRET so rotating one doesn't invalidate the others.

Issuing a token

Backend services authenticate the same way they do for /api/core/auth/verify — via x-forge-api-key.

curl
curl -X POST http://localhost:3030/api/core/resource-tokens/issue \
  -H "x-forge-api-key: fk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"resourceId": "img_123", "action": "read", "ttlSeconds": 300}'
200 OK
{
  "token": "eyJyZXNvdXJjZUlkIjoiaW1nXzEyMyIs...",
  "resourceId": "img_123",
  "action": "read",
  "expiresAt": "2026-09-06T16:05:00.000Z"
}

ttlSeconds defaults to 300 (5 minutes) and is capped at 3600 (1 hour). An optional metadata object is embedded in the token verbatim and returned unchanged on decode — useful for carrying small hints like an image variant ({"size": "thumb"}) without a second lookup.

Decoding a token

Decoding does not require an API key — the token itself is the credential, the same trust model as an S3 presigned URL. Whoever holds the token can ask Forge Core whether it's still valid and what it grants.

curl
curl -X POST http://localhost:3030/api/core/resource-tokens/decode \
  -H "Content-Type: application/json" \
  -d '{"token": "eyJyZXNvdXJjZUlkIjoiaW1nXzEyMyIs..."}'
200 OK
{
  "valid": true,
  "resourceId": "img_123",
  "action": "read",
  "issuedAt": "2026-09-06T16:00:00.000Z",
  "expiresAt": "2026-09-06T16:05:00.000Z",
  "metadata": null
}

Forge doesn't serve the resource itself

This is intentionally just the sign/verify primitive. Your app's own resource-serving layer calls decode, checks that resourceId/action match what's being requested, and only then fetches or streams the actual file.

Failure reasons

An expired, tampered, or malformed token returns 401 with {"valid": false, "reason": "..."}.

ReasonMeaning
malformedToken isn't the expected two-part signed format
invalid_signatureSignature doesn't match (tampered, or signed with a different secret)
expiredToken's expiry has passed

Related environment variable

  • FORGE_RESOURCE_TOKEN_SECRET — required at boot; the HMAC signing key for all resource tokens. See documentation/API.md for the full request/response shapes.