AWSAuth.EventStream (AWSAuth v1.4.0)

Copy Markdown View Source

AWS Signature Version 4 signing for event stream messages.

Some AWS APIs accept a stream of events from the client over a single connection (for example Amazon Transcribe streaming and Bedrock bidirectional streaming). Each event is individually signed, and the signatures form a chain: the first event is signed using the seed signature from the initial HTTP request's Authorization header, and each subsequent event is signed using the signature of the event before it.

The signature for an event is computed as:

string_to_sign =
  "AWS4-HMAC-SHA256-PAYLOAD" <> "\n" <>
  <amz_date>                 <> "\n" <>   # YYYYMMDDTHHMMSSZ
  <credential_scope>         <> "\n" <>   # YYYYMMDD/region/service/aws4_request
  <prior_signature>          <> "\n" <>   # hex
  sha256_hex(<header_bytes>) <> "\n" <>
  sha256_hex(<payload>)

signature = hmac_sha256(signing_key, string_to_sign)

High-level usage

sign_message/6 does the whole thing — encode the :date header, sign, and frame a wire-ready event stream message. Chain the returned signature into the next call:

seed = "..." # signature from the initial request's Authorization header
creds = AWSAuth.Credentials.from_env() |> Map.put(:region, "us-east-1")

{frame1, sig1} =
  AWSAuth.EventStream.sign_message(creds, "transcribe", seed, payload1, time1)

{frame2, sig2} =
  AWSAuth.EventStream.sign_message(creds, "transcribe", sig1, payload2, time2)

Low-level usage

sign_event/7 mirrors the canonical algorithm exactly (and matches the aws_signature Erlang library's sign_v4_event/7) when you want to control the encoded header bytes yourself.

Summary

Functions

Encodes a byte-array header (value type 6) into the AWS event stream binary format. The value is length-prefixed with a 16-bit big-endian length.

Frames serialized headers and a payload into a complete event stream message, including the prelude, prelude CRC, and message CRC.

Encodes a timestamp header (value type 8) into the AWS event stream binary format. The value is the milliseconds since the Unix epoch.

Signs a single event and returns the chunk signature as a lowercase hex string.

Signs an event and frames it as a wire-ready event stream message.

Functions

encode_byte_array_header(name, value)

Encodes a byte-array header (value type 6) into the AWS event stream binary format. The value is length-prefixed with a 16-bit big-endian length.

encode_message(headers, payload)

Frames serialized headers and a payload into a complete event stream message, including the prelude, prelude CRC, and message CRC.

Wire format

[total length      :: big-32]
[headers length    :: big-32]
[prelude CRC32      :: big-32]   # crc32 of the 8 prelude bytes above
[headers bytes]
[payload bytes]
[message CRC32      :: big-32]   # crc32 of everything before it

encode_timestamp_header(name, request_time)

Encodes a timestamp header (value type 8) into the AWS event stream binary format. The value is the milliseconds since the Unix epoch.

request_time may be a NaiveDateTime (interpreted as UTC) or a DateTime.

sign_event(credentials, service, prior_signature, header_bytes, payload, request_time, opts \\ [])

Signs a single event and returns the chunk signature as a lowercase hex string.

This is the low-level entry point. header_bytes must be the event's headers already serialized in the AWS event stream binary format (typically just the :date header — see encode_timestamp_header/2), and payload is the raw event payload.

Options:

  • :region - overrides the region from credentials
  • :raw - when true, returns the raw 32-byte signature instead of hex

Example

iex> creds = %AWSAuth.Credentials{
...>   access_key_id: "AKIDEXAMPLE",
...>   secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
...>   region: "us-east-1"
...> }
iex> header_bytes = <<5, 58, 100, 97, 116, 101, 8, 0, 0, 1, 137, 171, 187, 255, 224>>
iex> AWSAuth.EventStream.sign_event(
...>   creds,
...>   "transcribe",
...>   "ce2704cf5f348fd66f179d5883162f223c30b3fb8213fb1bc097bf2ecd34b1b5",
...>   header_bytes,
...>   "",
...>   ~N[2023-07-31 11:36:12]
...> )
"29ef82c39850abdcc65f9d6046f3e437e385112b80b7f17b31ba33a7da3cc8af"

sign_message(credentials, service, prior_signature, payload, request_time, opts \\ [])

Signs an event and frames it as a wire-ready event stream message.

Encodes the :date header from request_time, signs the message (using the encoded :date header as the signed headers and payload as the body), then builds the full event stream frame containing the :date and :chunk-signature headers followed by payload.

Returns {frame, signature_hex}. Pass signature_hex as the prior_signature for the next event in the stream.

Accepts the same options as sign_event/7 (except :raw).