Skip to main content
Secure your ogis instance with HMAC-SHA256 signature validation. When enabled, all requests must include a valid signature parameter.

When to Use Authentication

  • Private instances — Prevent unauthorized usage of your self-hosted ogis
  • Rate limiting — Control who can generate images
  • Usage tracking — Identify requests by signature
The public hosted service at img.ogis.dev does not require authentication.

Enabling Authentication

Set the OGIS_HMAC_SECRET environment variable on your server:
docker run -d \
  -p 3000:3000 \
  -e OGIS_HMAC_SECRET=your-secret-key-here \
  twango/ogis:latest
Choose a strong, random secret (32+ characters recommended):
# Generate a secure secret
openssl rand -hex 32

How It Works

  1. Client constructs query parameters (e.g., title=Hello&template=twilight)
  2. Parameters are sorted alphabetically and concatenated
  3. HMAC-SHA256 signature is computed using the secret
  4. Signature is appended to the URL as &signature=...
  5. Server verifies the signature before generating the image

Using the SDK

The SDK handles signing automatically when you provide hmacSecret:
import { OgisClient } from 'ogis';

const ogis = new OgisClient({
  baseUrl: 'https://ogis.example.com',
  hmacSecret: process.env.OGIS_SECRET  // Keep this secret!
});

// URLs are automatically signed
const url = ogis.generateUrl({
  title: 'My Secure Image',
  template: 'twilight'
});

// => https://ogis.example.com/?template=twilight&title=My+Secure+Image&signature=a1b2c3...

Manual Signing

If you’re not using the SDK, compute the signature manually.

Algorithm

  1. Collect all query parameters except signature
  2. Sort parameters alphabetically by key
  3. URL-encode and concatenate as key=value&key=value
  4. Compute HMAC-SHA256 of the string using your secret
  5. Hex-encode the result

Implementation Examples

import crypto from 'crypto';

function signOgisUrl(params: Record<string, string>, secret: string): string {
  // Sort parameters alphabetically
  const sortedKeys = Object.keys(params).sort();

  // Build canonical query string
  const canonical = sortedKeys
    .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
    .join('&');

  // Compute HMAC-SHA256
  const signature = crypto
    .createHmac('sha256', secret)
    .update(canonical)
    .digest('hex');

  return signature;
}

// Usage
const params = { title: 'Hello', template: 'twilight' };
const signature = signOgisUrl(params, 'your-secret');
const url = `https://ogis.example.com/?title=Hello&template=twilight&signature=${signature}`;

Error Responses

When authentication is enabled, invalid requests return:
StatusReason
401 UnauthorizedMissing signature parameter
401 UnauthorizedInvalid signature

Security Best Practices

Never expose your secret in client-side code or version control.
  1. Use environment variables — Store secrets in OGIS_SECRET or similar
  2. Rotate secrets periodically — Update your secret and redeploy
  3. Use HTTPS — Always serve your ogis instance over HTTPS to prevent signature interception

Server-Side Only

Generate signed URLs on your server, not in the browser:
// pages/api/og-image.ts
import { OgisClient } from 'ogis';

const ogis = new OgisClient({
  baseUrl: process.env.OGIS_URL!,
  hmacSecret: process.env.OGIS_SECRET!
});

export default function handler(req, res) {
  const { title } = req.query;
  const url = ogis.generateUrl({ title, template: 'twilight' });
  res.json({ url });
}