Loading...
Link protection

Explaining security mechanisms

Puzzle links can be simple, or they can be signed by your server. The right choice depends on how your site publishes media and how much control you want over where puzzle links can be used. Link security is configured separately for each media source.

Standard

Standard links are the easiest to set up and are suitable for many public media sources. They are a good starting point when your media is already public, when you are testing the integration, or when you want the fewest moving parts.

A Standard link includes client_id, media_url, and optional player_id. No server-side signing code is required.

Protected Media

Production integration is link-based, not iframe-based. If your media is already protected by your own paywall or member session, you may not need signed puzzle links. In that setup, players follow a normal link to a puzzle subdomain of your site, and your media server allows that subdomain to request media with the player's existing session.

For protected media, puzzlebaddie works best when media access is authorized by same-site cookies or by signed temporary media URLs. localStorage-based auth is not shared across subdomains and requires the partner to issue a playback URL or token.

The usual setup is to create a CNAME such as puzzles.yoursite.com that points to puzzlebaddie.com. Because the puzzle page is then on your domain, your site can allow the browser to send the media access cookie when the puzzle loads protected images or videos.

The puzzle subdomain must have valid HTTPS coverage. You can use a certificate issued specifically for puzzles.yoursite.com, a SAN certificate that includes it, or a wildcard certificate such as *.yoursite.com. If puzzlebaddie manages certificates for your puzzle host with ACME, the CNAME must be in place before certificate issuance and renewal can succeed.

Your media server should allow credentialed CORS requests from the puzzle subdomain. For example, if the puzzle page is served from https://puzzles.yoursite.com, media responses should include:

Access-Control-Allow-Origin: https://puzzles.yoursite.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, HEAD, OPTIONS
Access-Control-Allow-Headers: Range, Content-Type
Access-Control-Expose-Headers: Content-Length, Content-Range, Accept-Ranges
Vary: Origin

The cookie that protects media must be available to the jigsaw subdomain. Some sites do this with their existing session cookie scoped to the parent domain, such as .yoursite.com. A tighter option is to issue a separate media-access cookie that gives only enough permission to read puzzle media.

This approach keeps your media behind your own paywall while avoiding expiring media URLs that could break a long puzzle after a refresh. It does require DNS, HTTPS, cookie scope, and CORS to be configured correctly on your side.

The puzzle subdomain is intended for puzzle pages, player API calls, and required static assets. Partner dashboard and management pages remain on the puzzlebaddie management host. puzzlebaddie does not inject management-site analytics into partner puzzle pages.

A technical demo is available at https://TODO so your technical team can inspect the request flow and response headers.

Protected-media troubleshooting checklist

Check these items in order when public media works but protected media does not.

  1. Puzzle address: Confirm that the browser is on the puzzle host registered for the media source's client_id.
  2. DNS and HTTPS: Confirm that the puzzle-host CNAME points to puzzlebaddie and that its certificate covers the exact hostname.
  3. Media URL: Confirm that media_url begins with the registered media-source URL and opens for a signed-in user on the media site.
  4. CORS origin: Allow the exact puzzle origin, including https:// and any non-default port. The media response must return that origin in Access-Control-Allow-Origin, not * when credentials are used.
  5. Credentials: Return Access-Control-Allow-Credentials: true and ensure that image, video, audio, or fetch requests include credentials.
  6. Session cookie: In browser developer tools, confirm that the expected login cookie exists and is included in the protected-media request. Check its domain/path scope, Secure setting, and SameSite policy. Log in again after changing cookie settings.
  7. Read the failure: A missing Access-Control-Allow-Origin header indicates a CORS configuration problem. A 401 response means the request reached the media server but its session credential was missing or rejected.

High Security

High Security uses shared-key signing with HMAC-SHA256. puzzlebaddie generates a shared secret for the media source, and your server uses that secret to sign puzzle links before sending players to the puzzle page.

This prevents another website from copying one of your puzzle links, changing the media URL, and hosting puzzles with their own content or a different URL. If the link values change, the signature no longer matches.

Signed links should include an expiration time. Expiry limits how long a copied link remains useful and gives your site more control over puzzle access. The shared secret should stay only in server-side configuration.

Create High Security links only in server-side code. Never expose the shared secret in browser JavaScript, page source, templates sent to the browser, or public repositories.

Ultimate Security

Ultimate Security uses public-key signing with Ed25519. Your server signs puzzle links with a private key that stays on your server. puzzlebaddie stores only the public key, which can verify a link but cannot create one.

This gives the strongest separation: puzzlebaddie can confirm that a link was created by your system without needing the private key used to sign it.

Only the PUBLIC key should be pasted into puzzlebaddie. The private key should remain in your own server-side configuration or secret manager and should never be included in browser JavaScript.

Create Ultimate Security links only in server-side code. Never expose the private signing key in browser JavaScript, page source, templates sent to the browser, or public repositories.

What Signing Means

Signing creates a short proof that the link was created by someone who has the right secret or private key. The proof is sent in the URL as sig.

puzzlebaddie recomputes or verifies that proof before accepting the link. The signature should cover important values such as client_id, media_url, expires, and optional player_id.

If someone changes the media URL, client ID, player ID, or expiration time after the link is generated, verification fails.

Why Expiry Matters

A signature proves that a link was valid when your server created it. An expiration time says how long that link should remain valid.

Without expiry, a copied signed link could remain useful for a long time. With expiry, copied links naturally age out, which is usually what partners want for member pages, paid content, or time-sensitive access.

Open Partner Dashboard See Integration Example