Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Paseto Laravel Package

paragonie/paseto

Reference PHP implementation of PASETO security tokens (v3/v4): safer alternative to JWT/JWE/JWS with modern crypto. Supports local and public tokens, includes PASERK integration for key serialization/wrapping, and works with Sodium (or sodium_compat).

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require paragonie/paseto
    

    Ensure PHP 8.1+ with GMP, OpenSSL, and Sodium (or sodium_compat) extensions.

  2. First Use Case: Generate a symmetric key and create a local token:

    use ParagonIE\Paseto\Builder;
    use ParagonIE\Paseto\Keys\Base\SymmetricKey;
    
    $key = SymmetricKey::v4();
    $token = Builder::getLocal($key)
        ->setClaims(['user_id' => 123])
        ->toString();
    
  3. Verify a Token:

    use ParagonIE\Paseto\Parser;
    
    $parser = Parser::getLocal($key);
    $decoded = $parser->parse($token);
    

Where to Look First


Implementation Patterns

Core Workflows

1. Token Creation (Builder Pattern)

// Symmetric (local) token
$token = Builder::getLocal($key)
    ->setClaims(['role' => 'admin'])
    ->setExpiration((new DateTime())->add(new DateInterval('P1D')))
    ->toString();

// Asymmetric (public) token with PASERK
$publicKey = $privateKey->getPublicKey();
$token = Builder::getPublic($publicKey)
    ->setClaims(['email' => 'user@example.com'])
    ->toString();

2. Token Validation (Parser Rules)

$parser = Parser::getLocal($key)
    ->addRule(new \ParagonIE\Paseto\Rules\ValidAt) // Check `iat`, `nbf`, `exp`
    ->addRule(new \ParagonIE\Paseto\Rules\IssuedBy('my-app'))
    ->addRule(new \ParagonIE\Paseto\Rules\FooterJSON->setMaxKeys(5));

try {
    $decoded = $parser->parse($token);
} catch (\ParagonIE\Paseto\Exception\PasetoException $e) {
    // Handle invalid tokens (e.g., expired, tampered)
}

3. Key Rotation with Key Rings

// Receiving key ring for public tokens
$keyRing = new \ParagonIE\Paseto\ReceivingKeyRing()
    ->setVersion(new \ParagonIE\Paseto\Protocol\Version4())
    ->setPurpose(\ParagonIE\Paseto\Purpose::public())
    ->addKey('key-v1', $publicKeyV1)
    ->addKey('key-v2', $publicKeyV2);

$parser = Parser::getPublic($keyRing);
$decoded = $parser->parse($token); // Automatically tries all keys

4. Implicit Assertions (V3/V4)

// Builder
$token = Builder::getLocal($key)
    ->setImplicitAssertions(['tenant_id' => 42])
    ->setClaims(['user_id' => 123])
    ->toString();

// Parser (fails if tenant_id mismatch)
$parser = Parser::getLocal($key)
    ->setImplicitAssertions(['tenant_id' => 42]);
$parser->parse($token);

Integration Tips

  1. Laravel Integration:

    • Store keys in .env or Laravel’s config:
      // config/paseto.php
      return [
          'keys' => [
              'local' => env('PASETO_LOCAL_KEY'),
              'public' => env('PASETO_PUBLIC_KEY'),
          ],
      ];
      
    • Create a helper:
      // app/Helpers/Paseto.php
      use ParagonIE\Paseto\Builder;
      use ParagonIE\Paseto\Keys\Base\SymmetricKey;
      
      class PasetoHelper {
          public static function generateLocalToken(array $claims): string {
              $key = SymmetricKey::fromString(config('paseto.keys.local'));
              return Builder::getLocal($key)
                  ->setClaims($claims)
                  ->toString();
          }
      }
      
  2. Middleware for API Auth:

    // app/Http/Middleware/VerifyPasetoToken.php
    use ParagonIE\Paseto\Parser;
    use ParagonIE\Paseto\Keys\Base\SymmetricKey;
    
    class VerifyPasetoToken {
        public function handle($request, Closure $next) {
            $token = $request->bearerToken();
            $key = SymmetricKey::fromString(config('paseto.keys.local'));
            $parser = Parser::getLocal($key)
                ->addRule(new \ParagonIE\Paseto\Rules\ValidAt);
    
            $decoded = $parser->parse($token);
            $request->merge(['user' => $decoded->getClaims()]);
    
            return $next($request);
        }
    }
    
  3. Queue Jobs with Tokens:

    // Dispatch a job with a token payload
    $token = PasetoHelper::generateLocalToken([
        'job' => 'ProcessOrder',
        'order_id' => 123,
    ]);
    ProcessOrderJob::dispatch($token);
    
    // In the job
    $parser = Parser::getLocal($key);
    $claims = $parser->parse($token)->getClaims();
    
  4. Footers for Metadata:

    // Builder
    $token = Builder::getLocal($key)
        ->setClaims(['user_id' => 1])
        ->setFooterArray(['ip' => '192.168.1.1', 'user_agent' => 'Chrome'])
        ->toString();
    
    // Parser (with rules)
    $parser = Parser::getLocal($key)
        ->addRule(new \ParagonIE\Paseto\Rules\FooterJSON);
    $footer = $parser->parse($token)->getFooterArray();
    

Gotchas and Tips

Pitfalls

  1. Key Version Mismatch:

    • Error: TypeError if using a SymmetricKey with Version4 directly (must use Builder).
    • Fix: Always use Builder::getLocal($key) or Builder::getPublic($key).
  2. Sodium Extension Missing:

    • Error: Falls back to sodium_compat (slower, less secure).
    • Fix: Install Sodium: pecl install sodium or use a Docker image with Sodium preinstalled.
  3. Implicit Assertions Not Set:

    • Error: Parser silently accepts tokens if assertions aren’t set (security risk).
    • Fix: Always define assertions in both builder and parser:
      $builder->setImplicitAssertions(['tenant_id' => 42]);
      $parser->setImplicitAssertions(['tenant_id' => 42]);
      
  4. Footer JSON Rules Too Lenient:

    • Risk: Large/unexpected footers can cause DoS.
    • Fix: Enforce rules:
      $parser->addRule(
          new \ParagonIE\Paseto\Rules\FooterJSON()
              ->setMaxLength(1024)
              ->setMaxKeys(10)
      );
      
  5. Key Rotation Gaps:

    • Risk: Tokens signed with old keys may fail if not in the key ring.
    • Fix: Overlap keys during rotation:
      $keyRing->addKey('old-key', $oldPublicKey);
      $keyRing->addKey('new-key', $newPublicKey);
      

Debugging Tips

  1. Token Inspection:

    • Decode tokens manually to debug:
      $tokenParts = explode('.', $token);
      // $tokenParts[0] = version.purpose
      // $tokenParts[1] = ciphertext (local) or signature (public)
      
  2. Parser Errors:

    • Catch PasetoException and log the getMessage() for debugging:
      try {
          $parser->parse($token);
      } catch (PasetoException $e) {
          \Log::error('Paseto error: ' . $e->getMessage());
      }
      
  3. Key Validation:

    • Verify keys before use:
      if (!$key->isValidForVersion(new \ParagonIE\Paseto\Protocol\Version4())) {
          throw new \RuntimeException('Invalid key for version');
      }
      

Extension Points

  1. Custom Rules:
    • Extend \ParagonIE\Paseto\Rules\AbstractRule to validate claims:
      class CustomRule extends AbstractRule {
          public function validate(JsonToken $token): void {
              if ($token->getClaims()['role'] !== 'admin') {
                  throw new PasetoException
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui