Legacy Dev Forum Posts

 View Only

Sign Up

How to Handle Genesys AudioHook Authentication and Signature Comparison

  • 1.  How to Handle Genesys AudioHook Authentication and Signature Comparison

    Posted 06-05-2025 18:33

    fparejam | 2024-11-21 08:48:20 UTC | #1

    How to Handle Genesys AudioHook Authentication and Signature Comparison

    Hey everyone! I’ve been working with the Genesys AudioHook API and getting the authentication right was a bit trickier than expected. I saw some other devs having troubles on this forum as well... so, here’s a couple of Python and JavaScript examples to save you some time.

    This will show you how to build the canonical signature base, compute the HMAC-SHA256 signature, and make sure everything matches up.


    Example Request

    This is what the Genesys docs give us as an example GET request:

    GET /api/v1/voicebiometrics/ws HTTP/1.1
    Host: audiohook.example.com
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Key: SSdtIGEgV2ViU29ja2V0IQ==
    Sec-WebSocket-Version: 13
    User-Agent: GenesysCloud-AudioHook-Client
    Audiohook-Organization-Id: d7934305-0972-4844-938e-9060eef73d05
    Audiohook-Correlation-Id: e160e428-53e2-487c-977d-96989bf5c99d
    Audiohook-Session-Id: 30b0e395-84d3-4570-ac13-9a62d8f514c0
    X-API-KEY: SGVsbG8sIEkgYW0gdGhlIEFQSSBrZXkh
    Signature: sig1=:NZBwyBHRRyRoeLqy1IzOa9VYBuI8TgMFt2GRDkDuJh4=:
    Signature-Input: sig1=(”@request-target” “@authority” “audiohook-organization-id”
    “audiohook-session-id” “audiohook-correlation-id” “x-api-key”);
    keyid=“SGVsbG8sIEkgYW0gdGhlIEFQSSBrZXkh”;
    nonce=“VGhpc0lzQVVuaXF1ZU5vbmNl”;alg=“hmac-sha256”;created=1641013200;expires=3282026430
    
    
    It assumes the following configuration: 
    - Request URI: wss://audiohook.example.com/api/v1/voicebiometrics/ws
    - API Key: SGVsbG8sIEkgYW0gdGhlIEFQSSBrZXkh
    - Client Secret: TXlTdXBlclNlY3JldEtleVRlbGxOby0xITJAMyM0JDU=.

    Python example

    import base64
    import hashlib
    import hmac
    
    # Secret Key (Base64 encoded)
    CLIENT_SECRET = "TXlTdXBlclNlY3JldEtleVRlbGxOby0xITJAMyM0JDU="
    secret = base64.b64decode(CLIENT_SECRET)
    
    # Canonical Signature Base
    signature_base = (
        '"@request-target": /api/v1/voicebiometrics/ws\n'
        '"@authority": audiohook.example.com\n'
        '"audiohook-organization-id": d7934305-0972-4844-938e-9060eef73d05\n'
        '"audiohook-session-id": 30b0e395-84d3-4570-ac13-9a62d8f514c0\n'
        '"audiohook-correlation-id": e160e428-53e2-487c-977d-96989bf5c99d\n'
        '"x-api-key": SGVsbG8sIEkgYW0gdGhlIEFQSSBrZXkh\n'
        '"@signature-params": ("@request-target" "@authority" "audiohook-organization-id" '
        '"audiohook-session-id" "audiohook-correlation-id" "x-api-key");'
        'keyid="SGVsbG8sIEkgYW0gdGhlIEFQSSBrZXkh";nonce="VGhpc0lzQVVuaXF1ZU5vbmNl";'
        'alg="hmac-sha256";created=1641013200;expires=3282026430'
    )
    
    # Compute the HMAC-SHA256 signature
    computed_hash = base64.b64encode(
        hmac.new(secret, signature_base.encode("ascii"), hashlib.sha256).digest()
    ).decode("ascii")
    
    # Expected hash from the HTTP header
    expected_hash = "NZBwyBHRRyRoeLqy1IzOa9VYBuI8TgMFt2GRDkDuJh4="
    
    # Output results
    print("Computed Hash: ", computed_hash)
    print("Expected Hash: ", expected_hash)
    
    # Output
    "Computed Hash:  NZBwyBHRRyRoeLqy1IzOa9VYBuI8TgMFt2GRDkDuJh4="
    "Expected Hash:  NZBwyBHRRyRoeLqy1IzOa9VYBuI8TgMFt2GRDkDuJh4="

    Javascript Example

    const crypto = require('crypto');
    
    // Secret Key (Base64 encoded)
    const secret = Buffer.from('TXlTdXBlclNlY3JldEtleVRlbGxOby0xITJAMyM0JDU=', 'base64');
    
    // Canonical Signature Base
    const signature_base = [
        '"@request-target": /api/v1/voicebiometrics/ws',
        '"@authority": audiohook.example.com',
        '"audiohook-organization-id": d7934305-0972-4844-938e-9060eef73d05',
        '"audiohook-session-id": 30b0e395-84d3-4570-ac13-9a62d8f514c0',
        '"audiohook-correlation-id": e160e428-53e2-487c-977d-96989bf5c99d',
        '"x-api-key": SGVsbG8sIEkgYW0gdGhlIEFQSSBrZXkh',
        '"@signature-params": ("@request-target" "@authority" "audiohook-organization-id" ' +
        '"audiohook-session-id" "audiohook-correlation-id" "x-api-key");' +
        'keyid="SGVsbG8sIEkgYW0gdGhlIEFQSSBrZXkh";nonce="VGhpc0lzQVVuaXF1ZU5vbmNl";' +
        'alg="hmac-sha256";created=1641013200;expires=3282026430'
    ].join('\n');
    
    // Compute the HMAC-SHA256 signature
    const computed_hash = crypto.createHmac('sha256', secret).update(signature_base).digest('base64');
    
    // Expected hash from the HTTP header
    const expected_hash = "NZBwyBHRRyRoeLqy1IzOa9VYBuI8TgMFt2GRDkDuJh4=";
    
    // Output results
    console.log("Computed Hash: ", computed_hash);
    console.log("Expected Hash: ", expected_hash);
    
    //Output
    "Computed Hash:  NZBwyBHRRyRoeLqy1IzOa9VYBuI8TgMFt2GRDkDuJh4="
    "Expected Hash:  NZBwyBHRRyRoeLqy1IzOa9VYBuI8TgMFt2GRDkDuJh4="

    Things to Watch For

      1. Order Matters: The order in @signature-params must match what the client sends.
      2. Line Breaks Are Important: Use \n for line breaks in the canonical signature base after the headers and include the keyid, nonce, alg... with no spaces, in the exact same order it comes (it may be shuffled request after request).
      3. Byte-Level Precision: The computed signature is very sensitive to even the smallest differences, like extra spaces.

    Useful Links

    Here are some resources that might help:


    Wrapping Up

    I hope this makes your life easier! If you’re running into issues, double-check the signature base construction order and make sure everything is built dynamically in the same order that it comes (can change every time), and that it matches byte-for-byte.

    I hope this helped guys 😊

    Happy coding! 🚀

    Topic metadata

    audiohook, authentication, HMAC, HMAC-SHA256, signature verification, canonical signature base, websocket protocol change, websocket authentication, API security, Python API, JavaScript API, API integration, signature-input, X-API-Key, dynamic signature validation, real-time authentication, Genesys API example walkthrough, authentication tutorial


    system | 2024-12-22 08:49:01 UTC | #2

    This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.


    This post was migrated from the old Developer Forum.

    ref: 30500