The most fundamental requirement for any website to be secure is to use HTTPS (formally defined as HTTP over TLS, and preferably TLS 1.2 or 1.3). However, HTTPS alone does not satisfy every company's security needs. In the typical HTTPS usage, the server is authenticated to the client, but not vice-versa. (You can play with TLS client certificates, but they're too cumbersome for most software developers.) Certificate authorities can [behave abusively](https://arstechnica.com/security/2017/03/google-takes-symantec-to-the-woodshed-for-mis-issuing-30000-https-certs/) or [get outright hacked](https://threatpost.com/final-report-diginotar-hack-shows-total-compromise-ca-servers-103112/77170/). The defense-in-depth strategy for untrusted CAs is public-key pinning, but for PHP developers, enforcing [public-key pinning isn't straightforward](https://stackoverflow.com/a/39561602/2224584) (or always possible, depending on how old your software is). What if we told you we've developed a PHP library that solves all of these problems for your APIs, that works with PSR-7 HTTP messages, carries minimal added complexity, and just released the source code on Github? # Sapient: Secure API Toolkit Sapient is a PHP library that wraps [Guzzle](http://docs.guzzlephp.org/en/stable) and [sodium_compat](https://github.com/paragonie/sodium_compat) to add secure application-layer cryptography to your server-to-server HTTP requests. Some of its features, at a glance: * Operates on PSR-7 Request and Response objects (provided by Guzzle) * Public-Key Cryptography * Public-key Digital Signatures (Signing) * Public-key Message Encryption (Sealing) * Secret-Key Cryptography * Shared-key Message Authentication * Shared-key Message Encryption * Backwards-Compatibility with Unsecured APIs * Both Public-Key Signatures and Secret-Key Authentication add/verify an HTTP header but don't touch the message body at all * Servers that don't check the request headers will proceed as normal * Clients that don't check the response headers will proceed as normal * Clients/servers that **do** expect a request/response header will fail closed if one is not present
Get  paragonie/sapient  on Github
## Ed25519-Signed API Communications with Sapient Let's say you have an HTTP request you want to send to a Sapient-aware API, which is signed by a secret key only your application possesses. (Your API provider only knows your public key.) All you need to do is: 1. Pass your `Request` object to `Sapient::signRequest()` with your secret key. 2. Pass the `Response` object to `Sapient::verifySignedResponse()` with your API's public key. A detail client-side example of a secure two-way communication using PSR-7 looks like this:
<?php

use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\Sapient\Sapient;
use ParagonIE\Sapient\CryptographyKeys\SigningSecretKey;
use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
use ParagonIE\Sapient\Exception\HeaderMissingException;
use ParagonIE\Sapient\Exception\InvalidMessageException;

/* Load keys */
$clientSigningKey = new SigningSecretKey(
    Base64UrlSafe::decode(
        'AHxoibWhTylBMgFzJp6GGgYto24PVbQ-ognw9SPnvKppfti72R8By8XnIMTJ8HbDTks7jK5GmAnvtzaj3rbcTA=='
    )
);
$serverPublicKey = new SigningPublicKey(
    Base64UrlSafe::decode(
        'NvwsINZ-1y0F11xxed_FEUaL_MVewhdgF9tMYf5qEEw='
    )    
);

/* Initiate Sapient */
$sapient = new Sapient([
    'base_url' => 'https://api-provider.example.com'
]);

/** @var RequestInterface */
$request = $yourApp->getRequestToSend();

/* Create a signed request */
$signedRequest = $sapient->createSignedRequest(
    $request,
    $clientSigningKey
);

/* Get send the request to the server, grab the response */
$response = $sapient->send($signedRequest);
try {
    /* Verify the signature */
    $trustedApiResponse = $sapient->verifySignedResponse(
        $response,
        $serverPublicKey
    );
} catch (HeaderMissingException $exception) {
    /* No header added. */
    exit;
} catch (InvalidMessageException $exception) {
    /* Invalid signature */
    exit;
}
If you're building an API and you use Sapient in a PSR-7 middleware to sign your HTTP responses, non-Sapient clients that consume your API will be unaffected. At worst, they have one more HTTP header to disregard. Likewise, the converse is true: If you're building a Sapient API client that signs its HTTP requests, unless the non-Sapient API you're communicating with is *particularly* fussy about superfluous headers, this will not inhibit communication. However, if both sides are using Sapient, then downgrade attacks are no longer possible. If a signature is expected, it will not silently fail. ## Who Should Consider Adopting Sapient? First and foremost: **Payment Gateways**. In addition to digital signatures, Sapient allows quick and easy asymmetric encryption with a hard-coded public key that you can provide your users, which will in turn prevent a certificate authority meltdown from compromising the confidentiality of the messages sent over HTTPS.
$response = $sapient->send(
    $sapient->sealRequest($request, $serverX25519PublicKey)
);
$decrypted = $sapient->unsealResponse($response, $clientX25519SecretKey);
Beyond the realm of e-commerce, API clients and providers that either need a high degree of security or just want an easy way to mutually authenticate clients and servers should consider making their API gateway Sapient-compatible. ## Anticipated Questions ### Will Sapient be available in other languages besides PHP? Eventually, yes. Priority will be given to paid client work and our in-house development needs. If you need a library written in your favorite programming language, [get in touch](https://paragonie.com/contact). All of the cryptography is provided by libsodium, so [any language that has libsodium bindings](https://download.libsodium.org/doc/bindings_for_other_languages/) is a good candidate for a Sapient implementation. ### What is the roadmap for development? After our documentation and unit tests are up to snuff, we'll write a formal specification that details how to write compatible interfaces in other languages. Then, we will tag version 1.0, which will be supported until PHP 7.1 has reached end-of-life. Version 2.0, to be released in 2018, will require PHP 7.2 and not sodium_compat (since libsodium is going to be a core extension). ### Will Sapient support PHP 5? [No](https://paragonie.com/blog/2016/04/go-php-7-our-commitment-maintaining-our-open-source-projects). We're willing to develop a proprietary fork that supports PHP 5.6 (until it has reached end-of-life), but that will not be released to the general public. Upgrade to PHP 7 if you want better security and performance.