digest.hmac_sha256_base64

STRINGdigest.hmac_sha256_base64STRINGkeySTRINGs

Available inall subroutines.

Returns the HMAC-SHA256 of message using key, encoded as a Base64 string.

Parameters

ParameterTypeDescription
keySTRINGThe secret key for HMAC computation
messageSTRINGThe message to authenticate

The key is used directly as the HMAC key. For keys longer than 64 bytes (the SHA-256 block size), the key is first hashed with SHA-256 before use, as specified in RFC 2104.

Return value

Returns a 44-character Base64-encoded string representing the 256-bit (32-byte) HMAC, using standard Base64 encoding (RFC 4648 Section 4) with padding.

Example output: CV1aIf5tBkbbIj/fPeZDa7jfsvqwtRZ37PZEH89fKmc=

If key is empty or not set, the function returns an empty string (not set).

Base64 encoding

This function uses standard Base64 encoding as defined in RFC 4648 Section 4:

PropertyValue
AlphabetA-Za-z0-9+/
Padding= (always used)

For URL-safe Base64 output, apply digest.base64url_nopad to convert the result, or compute the hex version and convert with bin.hex_to_base64url_nopad().

Examples

Basic usage

declare local var.hmac STRING;
set var.hmac = digest.hmac_sha256_base64("secret-key", "hello world");
# Result: CV1aIf5tBkbbIj/fPeZDa7jfsvqwtRZ37PZEH89fKmc=

To verify this output using OpenSSL:

$ echo -n "hello world" | openssl dgst -sha256 -hmac "secret-key" -binary | openssl base64
CV1aIf5tBkbbIj/fPeZDa7jfsvqwtRZ37PZEH89fKmc=

Signing for an API that expects Base64 signatures

Many APIs expect Base64-encoded HMAC signatures:

sub vcl_recv {
declare local var.string_to_sign STRING;
declare local var.signature STRING;
declare local var.api_secret STRING;
set var.api_secret = table.lookup(api_keys, "service-secret");
if (var.api_secret == "") {
error 500 "API secret not configured";
}
set var.string_to_sign = req.http.Date + "\n" + req.url.path;
set var.signature = digest.hmac_sha256_base64(var.api_secret, var.string_to_sign);
set req.http.Authorization = "Signature " + var.signature;
}

Verifying a webhook with Base64 signature

sub vcl_recv {
declare local var.expected_sig STRING;
declare local var.secret STRING;
set var.secret = table.lookup(webhook_secrets, "stripe");
if (var.secret == "") {
error 500 "Webhook secret not configured";
}
set var.expected_sig = digest.hmac_sha256_base64(var.secret, req.body);
# Use constant-time comparison to prevent timing attacks
if (!digest.secure_is_equal(var.expected_sig, req.http.Stripe-Signature)) {
error 401 "Invalid signature";
}
}

Converting to URL-safe Base64

If you need URL-safe Base64 without padding (common in JWTs and URLs):

declare local var.hmac_b64 STRING;
declare local var.hmac_b64url STRING;
set var.hmac_b64 = digest.hmac_sha256_base64("secret-key", "hello world");
# Result: CV1aIf5tBkbbIj/fPeZDa7jfsvqwtRZ37PZEH89fKmc=
# Convert + to -, / to _, and remove padding
set var.hmac_b64url = regsuball(regsuball(var.hmac_b64, "\+", "-"), "/", "_");
set var.hmac_b64url = regsub(var.hmac_b64url, "=+$", "");
# Result: CV1aIf5tBkbbIj_fPeZDa7jfsvqwtRZ37PZEH89fKmc

Comparison with hex output

FunctionOutputLength
digest.hmac_sha2560x095d5a21fe6d0646db223fdf3de6436bb8dfb2fab0b51677ecf6441fcf5f2a6766 chars
digest.hmac_sha256_base64CV1aIf5tBkbbIj/fPeZDa7jfsvqwtRZ37PZEH89fKmc=44 chars

Base64 encoding is more compact (44 characters vs 66 for hex) and is often required by APIs and protocols.

Security considerations

Constant-time comparison

When comparing HMAC values for authentication, always use digest.secure_is_equal to prevent timing attacks. String comparison with == leaks information about which bytes matched, potentially allowing an attacker to forge valid authentication tags:

# CORRECT - constant-time comparison
if (digest.secure_is_equal(var.computed_hmac, req.http.X-Signature)) { ... }

Validate keys before use

Always check that key lookups succeed:

declare local var.key STRING;
set var.key = table.lookup(secrets, "api-key");
if (var.key == "") {
error 500 "API key not found";
}

Try it out

digest.hmac_sha256_base64 is used in the following code examples. Examples apply VCL to real-world use cases and can be deployed as they are, or adapted for your own service. See the full list of code examples for more inspiration.

Click RUN on a sample below to provision a Fastly service, execute the code on Fastly, and see how the function behaves.

Authenticate JSON Web Tokens at the edge

Decode the popular JWT format to verify user session tokens before forwarding trusted authentication data to your origin.