Skip to main content
Docs navigation

Authentication

How to make authenticated requests against the tile API. For how credentials are stored and protected, see the security model.

Two paths, same wire format

Tile endpoints accept either a short-lived access token minted from an API key, or — for app-mode keys (no origins registered) — the API key itself as a bearer credential. Both arrive as Authorization: Bearer … (or ?token= on the token path); the difference is lifetime and blast radius, not request shape.

  • Browsers: exchange a browser-mode key for an access token. 15-minute lifetime, origin-locked, plays well with @tilery/client and the offline cache.
  • Trusted backends, mobile, CI, scripts: use an app-mode key directly. One credential, no exchange call. Long-lived — only safe in environments you control end-to-end.
Browser-mode keys are rejected on direct use. Any key with one or more origins registered must go through the exchange endpoint — sending it as a Bearer to api.tilery.eu returns 401. This is enforced server-side; it is not an advisory.

Token exchange (browser path)

Your backend exchanges an API key for an access token at POST /api/tokens/exchange on the web origin (not the API origin). The ttl is optional and capped at 900 seconds (15 minutes). Browser-mode keys must use this path.

POST /api/tokens/exchange HTTP/1.1
Host: api.tilery.eu
Authorization: Bearer <api-key>
Content-Type: application/json

{ "ttl": 900 }

Re-exchange before exp. @tilery/client does this automatically.

Making an authenticated tile request

On the access-token path, pass the token as a ?token= query param on every tile, font, sprite, and style request. The query form is what @tilery/client uses — it avoids a CORS preflight that an Authorization header would trigger.

GET /map/tiles/vector/0/0/0?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIi... HTTP/1.1
Host: api.tilery.eu
Origin: https://yoursite.com

Direct API-key authentication (app-mode keys only)

App-mode keys (created without any registered origins) can be sent straight to the tile API as a bearer credential — skipping /api/tokens/exchange entirely. Convenient for server-to-server callers, but the credential is long-lived: a leak isn't bounded by a 15-minute TTL the way an access-token leak is, and the origin allowlist doesn't apply. See the security model for the tradeoff in full.

# App-mode key only (no origins registered).
# Long-lived credential — keep it on a backend you control.
curl -H "Authorization: Bearer $TILERY_API_KEY" \
  https://api.tilery.eu/map/tiles/vector/0/0/0 \
  -o tile.pbf

Only use this path from environments you fully control. Anywhere a browser or untrusted process can read the key, mint access tokens via the exchange endpoint instead.

Caching and token rotation

Because the access token lives in the URL, a naive browser cache treats each token rotation as a brand new URL and re-downloads every tile. The @tilery/client service worker fixes this by intercepting tile requests and normalizing the cache key (stripping ?token=), so repeat tiles stay served from the cache across rotations — and keep working offline.

Without the client SDK you lose this benefit. Use the SDK unless you have a specific reason not to.

Origin header check (browser path)

On the access-token path, requests that carry an Origin header (always the case from browsers) are matched against the allowlist configured per key under API Keys. A mismatch returns 403 Forbidden. Requests without an Origin header (server-to-server, curl, mobile apps) pass this check — CORS is a browser concept.

Direct API-key authentication doesn't enforce origins because app-mode keys have none registered; the safety boundary there is "the key never leaves a backend you trust." See the security model for configuration guidance.

Error statuses

StatusMeaningTypical cause
400Bad requestInvalid tile coordinates (zoom out of range, etc.).
401UnauthorizedMissing credential, expired access token, signature mismatch, revoked key, or a browser-mode API key sent directly without exchanging for an access token first.
402Payment requiredCredit balance exhausted (past the small grace allowance). Top up to resume serving — usage that slipped past the stop is collected from that top-up automatically.
403ForbiddenRequest Origin is not on your account's allowlist.
404Not foundCoordinates are valid but the archive has no tile at that position.
429Too many requestsPer-IP RPS limit exceeded, or brute-force block from too many recent auth failures. Not an empty credit balance — that's 402.

Related

  • Security model — credential storage, access-token internals, rate limits, and incident recovery.
  • API reference — try the exchange endpoint with your real key.