|
| 1 | +# API authentication |
| 2 | +## |
| 3 | + |
| 4 | +## Client library |
| 5 | + |
| 6 | +We provide a [php client](https://github.com/packagist/private-packagist-api-client) for the Private Packagist API. |
| 7 | +The client handles authentication, signature generation and access to all endpoints. |
| 8 | + |
| 9 | +Run `composer require private-packagist/api-client php-http/guzzle6-adapter` to install the client. |
| 10 | + |
| 11 | +### Basic usage |
| 12 | +```php |
| 13 | +$client = new \PrivatePackagist\ApiClient\Client(); |
| 14 | +$client->authenticate('api-key', 'api-secret'); |
| 15 | +$packages = $client->packages()->all(); |
| 16 | +``` |
| 17 | + |
| 18 | +## Authentication |
| 19 | + |
| 20 | +You can authenticate with the Private Packagist API using credentials, consisting of a public key and |
| 21 | +secret, that can be created in your organization settings under API Access. All API credentials are |
| 22 | +bound to a specific Private Packagist organization. |
| 23 | + |
| 24 | +API keys and secrets consists of three parts: a prefix, a random part, and an eight hexadecimal character long checksum. |
| 25 | +The prefix and checksum are designed to increase reliability of automatic scanning for secrets in your code base or leaked documents. |
| 26 | +These are the different prefixes: |
| 27 | + |
| 28 | +* `packagist_ack_`: API credential key |
| 29 | +* `packagist_acs_`: API credential secret |
| 30 | + |
| 31 | +### Supported headers |
| 32 | + |
| 33 | +The API expects a PACKAGIST-HMAC-SHA256 Authorization header to be present for every request. |
| 34 | + |
| 35 | +``` |
| 36 | +Authorization: PACKAGIST-HMAC-SHA256 |
| 37 | +Key=packagist_ack_ffce048835c6cdea47bcc4b73c79, |
| 38 | +Timestamp=1522925488, |
| 39 | +Cnonce=zjmfNVePGWoYksX/NJqnemb0g2dH30X3gu22JXqadZ0exBJsQZrC1xNYo10jyC6E, |
| 40 | +Signature=QXnRNGuXMOzd/dBnk1mbSUsA2M6ablgY+9y5/o/dIg4= |
| 41 | +``` |
| 42 | + |
| 43 | +The required values are: |
| 44 | + |
| 45 | +* [Required] **Key**: "API key" part of your organization's API Access credentials |
| 46 | +* [Required] **Timestamp**: The unix timestamp of the current time when creating the request by the API caller. The timestamp is valid within 15 seconds of the server time when the request is processed. |
| 47 | +* [Required] **Cnonce**: The UUID generated by the API caller. This header is used with the time stamp to prevent replay. |
| 48 | +* [Required] **Signature**: Signature string. See below< |
| 49 | + |
| 50 | +### Signature verification |
| 51 | + |
| 52 | +The signature calculation procedure is as follows: |
| 53 | + |
| 54 | +#### Organize the strings involved in the signature calculation |
| 55 | + |
| 56 | +```php |
| 57 | +$params = [ |
| 58 | + 'timestamp' => $time, |
| 59 | + 'cnonce' => $nonce, |
| 60 | + 'key' => $apiKey, |
| 61 | +]; |
| 62 | + |
| 63 | +if ($content) { |
| 64 | + $params['body'] => $content; |
| 65 | +} |
| 66 | + |
| 67 | +uksort($params, 'strcmp'); |
| 68 | + |
| 69 | +$stringToSign = |
| 70 | + $request->getMethod() . "\n" // all caps |
| 71 | + . $request->getHost() . "\n" // api host |
| 72 | + . $request->getPath() . "\n" |
| 73 | + . http_build_query($params, '', '&', PHP_QUERY_RFC3986); |
| 74 | +``` |
| 75 | + |
| 76 | + |
| 77 | +Each letter of the HTTPMethod value must be capitalized. |
| 78 | +The body must only be set if the request body is not empty. |
| 79 | + |
| 80 | +#### Calculate the signature |
| 81 | + |
| 82 | +```php |
| 83 | +$signature = base64_encode( |
| 84 | + hash_hmac('sha256', $stringToSign, $secret, true) |
| 85 | +); |
| 86 | +``` |
| 87 | + |
| 88 | +#### Pass the signature |
| 89 | + |
| 90 | +The base64 encoded hash must be sent for every request with the **Authorization** header. |
| 91 | + |
| 92 | +#### Authentication and signature errors |
| 93 | + |
| 94 | +**HTTP 401** |
| 95 | + |
| 96 | +The API token sent with the **Authorization** header is invalid or missing. |
| 97 | + |
| 98 | +**HTTP 400** |
| 99 | + |
| 100 | +The signature validation sent with the **Authorization** header is invalid. Issues may be: |
| 101 | + |
| 102 | +* "Request must contain a signature.": **Signature** value is missing or empty |
| 103 | +* "Request must contain a timestamp.": **Timestamp** value is missing or empty |
| 104 | +* "Timestamp is beyond the +-15 second difference allowed.": **Timestamp** value is not valid. |
| 105 | +* "Invalid signature": **Signature** value does not match expected value |
| 106 | + |
| 107 | +### Accessing API endpoints without generating a signature |
| 108 | + |
| 109 | +GET requests can also use a PACKAGIST-TOKEN Authorization header using your API key without generating a signature. |
| 110 | + |
| 111 | +``` |
| 112 | +Authorization: PACKAGIST-TOKEN ffce048835c6cdea47bc |
| 113 | +``` |
0 commit comments