Docs navigation
Security model
How Tilery stores credentials, validates tokens, and limits abuse. For how to actually make an authenticated request, see Authentication.
Credential model in one paragraph
API keys come in two modes. Browser-mode keys have one or more origins registered and are used only to mint short-lived access tokens (max 15 minutes) at /api/tokens/exchange; the access token then rides every tile fetch and is constrained by the per-key origin allowlist. App-mode keys have no origins and may be sent directly to the tile API as a Bearer credential — convenient for trusted backends, but long-lived and unguarded by an origin check, so blast radius on leak is bigger. Both modes are bounded by per-IP rate limits and your prepaid credit balance. TLS everywhere.
API key storage
- Generated server-side using a cryptographically secure random source.
- Only a hash is stored in the database. The plaintext key is displayed exactly once at creation and is not recoverable afterwards — copy it immediately.
- Deleting a key stops it from minting new access tokens. It does not invalidate tokens that were already issued — see below for why.
How access tokens are validated
Access tokens are self-contained, cryptographically signed JWTs: every tile fetch is validated from the signature and the exp claim alone, with no database lookup for the originating API key.
A consequence of that is that revocation isn't instant — a leaked access token remains usable until it expires. The 15-minute TTL ceiling bounds the window, and the origin allowlist and your finite credit balance bound what can be done inside it.
Origin allowlist
The allowlist is what makes a scraped access token useless on attacker-controlled pages. Browser requests carry an Origin header; the server rejects un-listed origins with 403. Paired with short TTLs, a leaked token is unusable outside your hostnames and unusable in total after 15 minutes.
The allowlist is configured per API key — register every hostname you serve from (prod, staging, dev, localhost), with port if it's non-default. Keep Allow any origin off unless you're developing locally; it bypasses the check entirely. See Authentication → Origin header check for the exact matching rules.
Direct API-key authentication: when, and the tradeoff
App-mode keys (created without any registered origins) can be sent straight to the tile API as Authorization: Bearer …, skipping the exchange step entirely. The motivating use cases are server-to-server backends, native mobile or desktop clients that proxy through their own server, CI jobs, and one-off scripts — environments where the credential never touches an end-user's browser.
The tradeoff vs. the access-token path:
- Lifetime. A leaked access token is unusable in ≤15 minutes. A leaked API key is usable until you revoke it — orders of magnitude bigger blast radius.
- Origin enforcement. Access tokens minted from browser-mode keys carry the per-key origin allowlist; the tile API rejects mismatched browsers with
403. App-mode keys have no origins to enforce, so the safety boundary is purely "the key never leaves a backend you control." - Bounding still works. Per-IP rate limits and your prepaid credit balance bound abuse identically on both paths — a stolen credential, token or key, can only burn roughly the credits you've prepaid before
402or429kicks in (usage counts against your balance within about two hours, so the stop can lag slightly behind the last tile).
401. This is a server-side guardrail, not a recommendation — the API enforces it so a key intended for browsers can't accidentally be treated as a bearer credential.Rate limits and the credit balance
- Per-IP RPS limit — sustained requests-per-second per client IP. Returns
429. Normal map rendering never comes close. - Auth failure limit — an IP racking up repeated failed auth attempts is temporarily blocked. Also
429. Brute-force protection, not a cost control. - Credit balance — each tile served comes out of your prepaid balance; once it runs out (past the overrun allowance, quantified on the pricing page), tiles return
402 Payment Requireduntil you top up. See Pricing.
Transport security
- All tile traffic is TLS. Tokens never traverse plaintext.
- Certificates are managed automatically via ACME.
What a public page can't fully prevent
Any access token your page ships to a browser is visible to anyone who loads the page — that's inherent to client-side integration, not a Tilery-specific limitation. If your site is public, somebody can scrape a token.
The layered defenses are there to bound the blast radius of that reality:
- The origin allowlist stops browsers on other sites from using a scraped token. It's enforced via the
Originheader, which browsers send automatically. A determined attacker calling from a script can forge any Origin they like — CORS is a browser concept, not a server-enforceable guarantee. - The 15-minute TTL caps how long a stolen token is useful.
- The prepaid credit balance caps total cost even under active abuse — the out-of-credit stop bounds an attacker to roughly what's on the account (usage counts against the balance within about two hours, so the cutoff can lag slightly behind the last tile).
Net: eliminating abuse is not possible for a public-page integration, but the layered defenses make it short-lived and bounded in cost. If "bounded" isn't good enough, the proxy pattern below keeps the access token off the client entirely.
Extra protection: proxy through your own backend
If your threat model needs more than short-lived access tokens plus the origin allowlist — for example, you want tiles gated by your own session/tenant rules, or you don't want the Tilery access token visible to end users at all — put Tilery behind your own backend.
The shape is straightforward: your backend authenticates the caller with whatever you already use (session cookies, your own API keys, mTLS, etc.), then forwards the call to tiles.tilery.eu with a Tilery access token attached server-side. The tile response streams back through you. Your callers never see a Tilery credential.
Tradeoffs: one extra network hop, you're on the hook for tile streaming and error mapping, and you lose the @tilery/client service-worker cache — but you can cache tiles in your own CDN or origin instead, and you get to enforce any per-user rule you want.
Best practices
- Keep API keys on the server. Your backend exchanges them for access tokens — never ship a key to a browser or mobile app.
- Use the access-token path for anything browser-reachable. Direct API-key authentication is only safe in environments you control end-to-end (server-to-server, native-app-via-your-own-proxy, CI). The 15-minute token lifetime is what bounds a leak from a public-page integration.
- Lock down origins. The allowlist is per API key — list every hostname you legitimately serve from, and keep Allow any origin off except during local development.
- Separate environments. One API key per environment (production, staging, local). Revoking a compromised key doesn't take down the others.
- Rotate keys periodically. Deleting an old key stops new access tokens being minted; any already-issued tokens drain out within 15 minutes.
- Don't commit keys. Keep API keys in env vars or a secret manager, never in version control.
- Watch your usage dashboard. Unexpected spikes can indicate a compromised token — alert on your own metrics if you can.
If an API key is leaked
Access tokens are expected to be visible in browser URLs — that's what the TTL, origin allowlist, and prepaid balance are for. A leaked access token is a bounded event, not an incident.
An API key is different. It's supposed to stay on your backend; if one gets out, it can be used to mint fresh access tokens indefinitely (browser-mode) or hit the tile API directly (app-mode). Remediation:
- Revoke the key from the dashboard immediately. Direct API-key calls stop working as soon as the resolver cache turns over (seconds); browser-mode keys can no longer mint new access tokens.
- Access tokens already minted from a browser-mode key remain valid until their
exp(≤15 minutes). Plan for that window. - Create a new key and rotate your backend env vars.
- Review access logs for suspicious activity.
Related
- Authentication — the transport mechanics: exchange endpoint, query param vs header, error statuses.
- Manage API keys (requires login).