AnsweredAssumed Answered

Establishing Ruby Connection to Akamai REST API (Security Monitor, etc.) - Not Authorized (401): "The signature does not match"

Question asked by Kurt Wondra on May 25, 2016
Latest reply on Jun 12, 2016 by Dejan Golja

Hi there,


I am trying to gather some data from the various Akamai APIs which all seem to share the same process for authentication/authorization.


I have spent several hours trying to get a connection established, however I am still having trouble running a basic GET request against "/security-monitor/v1/report-packs".  I have been granted authorization to this API by an administrator.  The access is Read Only but I assume that will be sufficient to basic data gathering like this.


I followed the API Client Authentication  guide verbatim as best as I can gather, but I am receiving the error The signature does not match in the JSON response.


My request seems to take into account everything the API is expecting according to the documentation.  I tested modifying the `client_token`, `access_token`, and `secret` and they all throw very specific error messages (which indicates they are correct).  I also tested to make sure the timestamp requires are being met and they are (changing the timestamp back several hours will produce an invalid timestamp response from the API).


I am stumped.  Any help is greatly appreciated!




    require 'net/http'
    require 'uri'
    require 'json'
    require 'openssl'
    require 'base64'

    # Attributes required for Akamai API Connection
    base_url = 'akab-*********************************'
    signing_timestamp ="%Y%m%dT%H:%M:%S-0700").to_s
    nonce = '************************************'

    # Client Token, Access Token, and Secret (received from Akamai API export)
    client_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    access_token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

    # Signing Key (Base 64 Encoded) - the timestamp is being signed using the Client Secret as the key.  Uses HMAC-SHA256 as suggested.
    signing_hash  = OpenSSL::HMAC.digest('sha256', secret, signing_timestamp)
    key = Base64.encode64(signing_hash).chomp

    # Request Data = Exactly as shown in the API 'Client Authentication' documentation sample
    data =  "GET\thttps\t#{base_url}\t/security-monitor/v1/report-packs\t\t\tEG1-HMAC-SHA256client_token=#{client_token};access_token=#{access_token};timestamp=#{signing_timestamp};nonce=#{nonce};"

    # EdgeGrid Request Signature - Same process as above, but this time we're sigining the 'Data to Sign' with the 'Signing Key'
    signature_hash  = OpenSSL::HMAC.digest('sha256', key, data)
    signature = Base64.encode64(signature_hash).chomp

    # Put it all together in one nice string to be used as the Authorization header below
    akamai_req = "EG1-HMAC-SHA256 client_token=#{client_token};access_token=#{access_token};timestamp=#{signing_timestamp};nonce=#{nonce};signature=#{signature}"

    uri = URI.parse("https://#{base_url}/security-monitor/v1/report-packs")

    proxy = Net::HTTP::Proxy('', '80', 'proxy_user', 'proxy_pass')

    req =

    req['Authorization'] = akamai_req

    result = proxy.start(,uri.port, :use_ssl => uri.scheme == 'https', :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|

    # Print the result of the GET request -- this is what produces the error below
    puts result.body


Here is the output of 'puts data.inspect' -- this is the "Data To Sign" the documentation references:




Here is the output of 'puts akamai_req.inspect' -- this is the Authorization header:


"EG1-HMAC-SHA256 client_token=akab-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;access_token=akab-*********************************;timestamp=20160526T04:04:18-0700;nonce=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;signature=******************************************"


The result of the above code is as follows:


  "type": "",
  "title": "Not authorized",
  "status": 401,
  "detail": "The signature does not match",
  "instance": "https://akab-*********************",
  "method": "GET",
  "serverIp": "x.x.x.x",
  "clientIp": "x.x.x.x",
  "requestId": "7028eb1e",
  "requestTime": "2016-05-25T23:47:35Z"