API requests are authenticated using credentials comprised of an access key and a secret key.
You can think of the access key as a username. A single worker may have multiple access keys with varying permissions for each application or service that uses the API, and each of them would have their own secret key.
Similarly, the secret key is like a password. However, unlike a traditional password, the secret key isn’t directly transmitted back to the server for verification. Instead, the secret key is combined with public details about the HTTP request (verb, path, date, query string, payload) to cryptographically sign it. Since the server also knows the secret key for each access key, it can create its own signature using the same combination of secret key and HTTP request details. If the signatures match then the request is authenticated.
Creating an API key-pair
First, enable the Web API plugin and create a key-pair.
Authenticating with the provided libraries
The process of signing a request is automatically handled by the official libraries for PHP, Perl, Python, and Node.js.
Authenticating from custom scripts
To sign an API request manually, create an MD51 signature of the following string:
verb\n http_date\n url_path\n url_query_string\n payload\n secret\n
The verb of the HTTP request:
DELETE. This prevents the signature of a previous request from being reused with a different verb.
The RFC-2822 formatted
Date:header being sent with the request. The current date should be used, but the server will tolerate a difference of no more than 10 minutes. This prevents the signature of a previous request from being reused at a later date (a “replay attack”2).
The relative path of the request, without the scheme, host, or query string. For example, in the URL
https://cerb.example/rest/tickets/123.json?expand=latest_message_content, the path is
The query string parameters sorted in alphabetical order. For example, the parameters
status=activewould be sorted as
The body of a
POSTrequest, or blank otherwise.
The secret key as a lowercase MD5 hash.
The generated signature should be sent with the request as a header in the following format:
If you're having trouble authenticating and you're sure that the signature is correct, verify that the current time is accurate on both the client and server.
All of these security considerations are moot if your secret key isn't stored securely. Make sure that custom scripts aren't world-readable on the server. You should always give API credentials the least amount of privileges required to perform the desired actions.
Let’s look at an example signature for testing your own authentication implementation.
For this request:
POST /rest/tickets/search.json?show_meta=0 HTTP/1.1 Date: Wed, 08 Feb 2017 19:53:35 GMT Content-Type: application/x-www-form-urlencoded; charset=utf-8 Host: cerb.example Connection: close Content-Length: 27 expand=custom_&q=status%3Ao
Using these credentials:
- Access key:
- Secret key:
The authentication header is comprised of
In PHP, the signature is generated as follows:
$secret_hash = md5('fw4y9fjjd5tqjlsk3u9zkjjr154xbftc'); $string_to_sign = <<< EOF POST Wed, 08 Feb 2017 19:53:35 GMT /rest/tickets/search.json show_meta=0 expand=custom_&q=status%3Ao $secret_hash EOF; echo md5($string_to_sign);