HMAC Authentication & Security

Secure your HMAC-signed OG image URLs with FastOG's HMAC-SHA256 authentication. This guide covers signing, validating, and troubleshooting every request, so you can ship dynamic Open Graph images on the fly β€” credit-based per render. Sign up free for 100 credits, then create your API key and HMAC secret in the dashboard (renders are watermarked until your first payment). Sign on your server once and integrate in minutes.

πŸš€ Quick Start

New to HMAC signing? Start here:
  • Quick Start Guide β€” Get up and running in 5 minutes
  • JavaScript Tutorial β€” Complete guide for Node.js/Next.js developers
  • PHP Tutorial β€” Coming soon
  • Python Tutorial β€” Coming soon
  • πŸ“š Documentation Index

    Core Concepts

    • HMAC Signature Guide β€” Complete reference with algorithm details, requirements, and examples in JavaScript, PHP, and Python
    • HMAC Validation β€” Server-side implementation details, security features, and error responses

    Tutorials

    - Quick Start (5 minutes)

    - Next.js App Router (3 patterns)

    - Next.js Pages Router

    - Express.js Backend

    - Vanilla Node.js

    - Frontend Integration Patterns (SSG, SSR, Client-Side)

    - Testing & Debugging

    - Common Pitfalls

    Quick Reference

    Algorithm

    message = method + path + timestamp + apiKey
    signature = HMAC-SHA256(message, hmac_secret)
    
    URL: /api/v1/og?title=Hello&key=sk_quick_123abc&s=<signature>&t=<timestamp>

    Query Parameters

    ParameterDescriptionExample
    keyFull API keysk_quick_123abc
    sHMAC-SHA256 signature (64 hex chars)9f8a1b2c3d4e...
    tUnix timestamp in seconds1722718800

    Error Codes

    CodeHTTP StatusDescription
    missing_signature401Missing s, t, or key parameter
    invalid_signature_format401Signature not 64 hex characters
    expired_timestamp401Timestamp > 5 minutes old
    invalid_signature401Signature doesn't match
    missing_api_key401Missing API key

    🎯 Use Cases

    Blog Posts

    Generate dynamic OG images for blog posts:

    javascript
    const ogUrl = generateSignedOgUrl({
        template: "blog",
        title: post.title,
        subtitle: post.excerpt,
        author: post.author.name,
    });
    
    // <meta property="og:image" content="{ogUrl}" />

    E-commerce Products

    Create OG images for product pages:

    javascript
    const ogUrl = generateSignedOgUrl({
        template: "ecommerce",
        title: product.name,
        price: product.price,
        image: product.image,
    });

    User Profiles

    Generate OG images for user profiles:

    javascript
    const ogUrl = generateSignedOgUrl({
        template: "profile",
        name: user.name,
        avatar: user.avatarUrl,
        bio: user.bio,
    });

    πŸ” Security

    Best Practices

  • Store secrets securely β€” Use environment variables or secrets manager
  • Never expose HMAC secret in client-side code β€” Sign on server only
  • Use HTTPS β€” Prevents MITM attacks
  • Rotate secrets periodically β€” Especially if compromised
  • Monitor failed signatures β€” Repeated failures may indicate attacks
  • Per-user isolation β€” Each API key has its own HMAC secret
  • Getting Your HMAC Secret

  • Go to Dashboard β†’ API Keys
  • Create a new API key
  • Copy the HMAC Secret (shown only once!)
  • Store in environment variables
  • bash
    # .env
    FASTOG_HMAC_SECRET=<your-64-char-hex-secret>

    πŸ§ͺ Testing

    Generate Test URL

    bash
    # Node.js
    node -e "
    const crypto = require('crypto');
    const ts = Math.floor(Date.now() / 1000);
    const msg = 'GET/api/v1/og' + ts + 'sk_quick_123abc';
    const sig = crypto.createHmac('sha256', 'YOUR_HMAC_SECRET').update(msg).digest('hex');
    console.log('https://fastog.com/api/v1/og?title=Test&key=sk_quick_123abc&s=' + sig + '&t=' + ts);
    "

    Test with curl

    bash
    curl "https://fastog.com/api/v1/og?title=Test&key=sk_quick_123abc&s=<signature>&t=<timestamp>"

    Expected Responses

    • βœ… Valid signature β†’ Returns OG image (or 422 if template params invalid)
    • ❌ Expired timestamp β†’ {"code": "expired_timestamp"}
    • ❌ Invalid signature β†’ {"code": "invalid_signature"}
    • ❌ Missing params β†’ {"code": "missing_signature"}

    πŸ›  Troubleshooting

    Signature doesn't match

  • Verify you're using the correct HMAC secret (check API key in dashboard)
  • Ensure timestamp is in seconds, not milliseconds
  • Check message format: method + path + timestamp + apiKey (no separators)
  • Verify signature is lowercase hex (64 characters)
  • Timestamp expired

    • Ensure server clock is synchronized (use NTP)
    • Generate timestamp immediately before making request
    • Maximum allowed drift: 5 minutes

    API key not found

    • Verify you're using the full API key (e.g. sk_quick_123abc)
    • Check the API key exists in dashboard
    • Ensure key hasn't been revoked

    πŸ“– Additional Resources

    ❓ FAQ

    Q: Why query parameters instead of headers?

    A: OG images are fetched by social network crawlers (LinkedIn, Twitter, Facebook) that don't send custom headers. The signature MUST be in the URL.

    Q: Can I use the same signature for multiple requests?

    A: No. Each signature is tied to a specific timestamp and expires after 5 minutes.

    Q: Do I need to sign requests for all templates?

    A: Yes. All requests to /api/v1/og require HMAC signatures.

    Q: What happens if my HMAC secret is compromised?

    A: Revoke the API key in the dashboard and create a new one. Each API key has its own HMAC secret.

    Q: Can I disable HMAC validation for internal services?

    A: Contact support for custom solutions. HMAC validation is mandatory for all public API endpoints.

    πŸ†˜ Support

    Need help?


    Last Updated: 2026-08-03 Version: 1.0

    Related

    Try it free β€” no signup required

    Preview and test dynamic OG images in seconds.

    Open the Free OG Image Tester