Skip to content

Latest commit

 

History

History

docs

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

PASETO (PHP) Documentation

If you're not already familiar with PASETO, you can learn more about its features here. If you were using an older version of PASETO, the migration guide is worth a read.

Most of the supporting documentation has been moved to the PASETO specification repository.

How to use the PHP library

The first thing you should know about this library is it tries to accomplish type-safety by wrapping cryptographic keys inside of objects. For example:

<?php
use ParagonIE\Paseto\Keys\{Base\AsymmetricSecretKey,Base\SymmetricKey};

$privateKey = new AsymmetricSecretKey(sodium_crypto_sign_keypair());
$publicKey = $privateKey->getPublicKey();

$sharedKey = new SymmetricKey(random_bytes(32));

You can access the key's internal strings by invoking $key->raw().

Storing asymmetric keys

If you need to store the keys on your server, you can encode/decode the key.

<?php
use ParagonIE\Paseto\Keys\Base\{AsymmetricPublicKey, AsymmetricSecretKey};

$privateKey = new AsymmetricSecretKey(sodium_crypto_sign_keypair());
$publicKey = $privateKey->getPublicKey();

$privateKeyEncoded = $privateKey->encode();
$publicKeyEncoded = $publicKey->encode();

$privateKeyDecoded = AsymmetricSecretKey::fromEncodedString($privateKeyEncoded);
$publicKeyDecoded = AsymmetricPublicKey::fromEncodedString($publicKeyEncoded);

Or export as PEM format, and reimport from PEM.

<?php
use ParagonIE\Paseto\Keys\Base\{AsymmetricPublicKey, AsymmetricSecretKey};

$privateKey = new AsymmetricSecretKey(sodium_crypto_sign_keypair());
$publicKey = $privateKey->getPublicKey();

$privateKeyEncoded = $privateKey->encodePem();
$publicKeyEncoded = $publicKey->encodePem();

$privateKeyDecoded = AsymmetricSecretKey::importPem($privateKeyEncoded);
$publicKeyDecoded = AsymmetricPublicKey::importPem($publicKeyEncoded);

No version of the protocol will let you misuse a key by accident. This will generate a TypeError:

<?php
use ParagonIE\Paseto\Keys\Base\SymmetricKey;use ParagonIE\Paseto\Protocol\Version4;

/**
 * We assume the same key $sharedKey was used from above.
 * @var SymmetricKey $sharedKey
 */
 
$token = Version4::sign('some arbitrary data', $sharedKey);

Building and Verifying Pasetos

The simplest use-case is to use shared-key authentication to achieve tamper-resistant tokens:

<?php
use ParagonIE\Paseto\Builder;use ParagonIE\Paseto\Keys\Base\SymmetricKey;use ParagonIE\Paseto\Protocol\Version4;use ParagonIE\Paseto\Purpose;

/**
 * We assume the same key $sharedKey was used from above.
 * @var SymmetricKey $sharedKey
 */
$token = Builder::getLocal($sharedKey, new Version4);

$token = (new Builder())
    ->setKey($sharedKey)
    ->setVersion(new Version4)
    ->setPurpose(Purpose::local())
    // Set it to expire in one day
    ->setIssuedAt()
    ->setNotBefore()
    ->setExpiration(
        (new DateTime())->add(new DateInterval('P01D'))
    )
    // Store arbitrary data
    ->setClaims([
        'example' => 'Hello world',
        'security' => 'Now as easy as PIE'
    ]);
echo $token; // Converts automatically to a string

Decoding tokens

First, you need to define your Parser rules.

  • Which versions of the protocol do you wish to allow? If you're only using v2 in your app, you should specify this.
<?php
use ParagonIE\Paseto\Exception\PasetoException;use ParagonIE\Paseto\JsonToken;use ParagonIE\Paseto\Keys\Base\SymmetricKey;use ParagonIE\Paseto\Parser;use ParagonIE\Paseto\ProtocolCollection;use ParagonIE\Paseto\Purpose;use ParagonIE\Paseto\Rules\{IssuedBy,ValidAt};

/**
 * We assume the same key $sharedKey was used from above.
 * $providedToken is $token (as a string) from the previous snippet.
 *
 * @var string $providedToken
 * @var SymmetricKey $sharedKey
 */
$parser = Parser::getLocal($sharedKey, ProtocolCollection::v4())
    ->addRule(new ValidAt)
    ->addRule(new IssuedBy('issuer defined during creation'));

// This is the same as:
$parser = (new Parser())
    ->setKey($sharedKey)
    // Adding rules to be checked against the token
    ->addRule(new ValidAt)
    ->addRule(new IssuedBy('issuer defined during creation'))
    ->setPurpose(Purpose::local())
    // Only allow version 4
    ->setAllowedVersions(ProtocolCollection::v4());

try {
    $token = $parser->parse($providedToken);
} catch (PasetoException $ex) {
    /* Handle invalid token cases here. */
}
var_dump($token instanceof JsonToken);
// bool(true)

Key Rings

A key ring is a set of named cryptographic keys.

Support for key rings is totally optional. If you don't need them, don't build support for them in your application. If you do need support for them, we've provided a first-class implementation.

Key rings are useful for integrating with multiple third-party identity providers, or adding mechanisms to enforce key-rotation with a window of overlap between two keys.

Here's an example:

<?php
use ParagonIE\Paseto\Keys\Base\AsymmetricPublicKey;use ParagonIE\Paseto\Keys\Base\SymmetricKey;use ParagonIE\Paseto\Protocol\Version4;use ParagonIE\Paseto\Purpose;use ParagonIE\Paseto\ReceivingKeyRing;

/**
 * @var SymmetricKey $localKey
 * @var AsymmetricPublicKey $pk1
 * @var AsymmetricPublicKey $pk2
 */
$keyring = (new ReceivingKeyRing())
    ->setVersion(new Version4)
    ->setPurpose(Purpose::public())
    ->addKey('gandalf0', $pk1)
    ->addKey('legolas1', $pk2);

$otherKeyring = (new ReceivingKeyRing())
    ->setVersion(new Version4)
    ->setPurpose(Purpose::local())
    ->addKey('boromir2', $localKey);

As you can see, each KeyRing object can be locked down to a given version and purpose. If you try to add an AsymmetricPublicKey to $otherKeyring, it will throw an exception.

$otherKeyring->addKey('gandalf0', $pk1); // throws

There is also a SendingKeyRing class, which behaves mostly the same way as ReceivingKeyRing, but only allows Sending Keys (SymmetricKey, AsymmetricSecretKey).

Using Key Rings in Builders and Parsers

The Parser and Builder classes both support Key Rings without additional logic necessary. Users are only responsible for correctly configuring their Key Ring to specify which version and purpose is permitted.

<?php
use ParagonIE\Paseto\{
    Builder,
    Parser,
    ReceivingKeyRing,
    SendingKeyRing
};
/**
 * @var Builder $builder
 * @var Parser $parser
 * @var ReceivingKeyRing $rcvKeyRing
 * @var SendingKeyRing $sendKeyRing
 */

// Building a token with a SendingKeyRing
$builder->setKey($sendKeyRing);
$token = $builder->toString();

// Parsing a token with a ReceivingKeyRing
$parser->setKey($rcvKeyRing);
$valid = $parser->parse($token);