PHP Logolcobucci/jwt

What is lcobucci/jwt?
`lcobucci/jwt` is a popular, robust, and well-maintained PHP library for working with JSON Web Tokens (JWTs). It provides a comprehensive set of features for creating, parsing, and validating JWTs according to the RFC 7519 specification.

What are JSON Web Tokens (JWTs)?
JSON Web Tokens (JWTs) are an open, industry-standard RFC 7519 method for representing claims securely between two parties. They are widely used for authentication and authorization in modern web applications, especially in RESTful APIs and microservices architectures.

A JWT typically consists of three parts, separated by dots (.), which are Base64Url-encoded:
1. Header: Contains the token type (JWT) and the signing algorithm being used (e.g., HS256, RS256).
2. Payload (Claims): Contains statements about an entity (typically, the user) and additional data. Claims can be registered (standardized claims like `iss`, `exp`, `sub`), public (custom claims defined by users but collision-resistant), or private (custom claims agreed upon by the parties using them).
3. Signature: Created by taking the encoded header, the encoded payload, a secret key, and the algorithm specified in the header. This signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message hasn't been tampered with.

How `lcobucci/jwt` Helps:
`lcobucci/jwt` simplifies the complex process of handling JWTs in PHP applications by offering:

* Builder API: Allows you to construct JWTs programmatically, setting various claims (issuer, audience, expiration time, custom data, etc.) and signing them with different algorithms (HMAC, RSA, ECDSA).
* Parser API: Enables parsing a JWT string back into a token object, allowing easy access to its header and payload claims.
* Validator API: Provides mechanisms to validate parsed tokens against a set of constraints (e.g., checking if the token is expired, if it was issued by a trusted party, if it's meant for the current audience). It also verifies the token's signature to ensure its integrity and authenticity.
* Key Management: Supports various key types for different signing algorithms, allowing secure handling of secrets or private/public key pairs.
* Extensibility: Designed with extensibility in mind, allowing developers to implement custom claims, signers, or validation rules.

By separating the concerns of building, parsing, and validating, `lcobucci/jwt` offers a clear and robust API for secure JWT implementation in PHP projects.

Example Code

```php
<?php

require 'vendor/autoload.php';

use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Validation\Constraint\IssuedBy;
use Lcobucci\JWT\Validation\Constraint\PermittedFor;
use Lcobucci\JWT\Validation\Constraint\ValidAt;
use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
use Lcobucci\Clock\SystemClock;
use Lcobucci\JWT\Token\Plain;

// --- Configuration for building and parsing tokens ---

// A secret key for HMAC signing. In a real application, this should be a strong, random string
// and securely stored (e.g., in environment variables).
$jwtSecret = 'a-super-secret-key-that-no-one-else-should-know-1234567890';
$signingKey = InMemory::plainText($jwtSecret);

// Configuration for building tokens
// Here we use HMAC SHA256. For RSA, you would use Signer\Rsa\Sha256 and different key types.
$configBuilder = Configuration::forSymmetricSigner(
    new Sha256(),
    $signingKey // Signing key
);

// Configuration for parsing and validating tokens
// The validation configuration needs the public key or the same secret key for symmetric algorithms.
$configParser = Configuration::forSymmetricSigner(
    new Sha256(),
    $signingKey // Verification key
);

// --- Building a JWT ---

echo "\n--- Building a JWT ---\n";

$builder = $configBuilder->builder();

$now = new DateTimeImmutable();

$token = $builder
    ->issuedBy('http://example.com') // Configures the issuer (iss claim)
    ->permittedFor('http://example.org') // Configures the audience (aud claim)
    ->identifiedBy('4f1g2h3i4j5k6l7m8n9o0p1q2r3s4t5u') // Configures the id (jti claim), a JWT unique identifier
    ->issuedAt($now) // Configures the time that the token was issued (iat claim)
    ->canOnlyBeUsedAfter($now->modify('+1 minute')) // Configures the time that the token can be used (nbf claim)
    ->expiresAt($now->modify('+1 hour')) // Configures the expiration time of the token (exp claim)
    ->withHeader('foo', 'bar') // Configures a header item
    ->withClaim('uid', 123) // Configures a custom claim with the name 'uid'
    ->withClaim('roles', ['admin', 'user']) // Configures another custom claim
    ->getToken($configBuilder->signer(), $configBuilder->signingKey()); // Builds a new token and signs it

// The token is an instance of Lcobucci\JWT\Token\Plain
$tokenString = $token->toString();

echo "Generated Token: " . $tokenString . "\n";

// --- Parsing and Validating a JWT ---

echo "\n--- Parsing and Validating a JWT ---\n";

$parser = $configParser->parser();

try {
    // Parse the token string back into a Token object
    / @var Plain $parsedToken */
    $parsedToken = $parser->parse($tokenString);

    // Create a validator
    $validator = $configParser->validator();

    // Define validation constraints
    // Use LooseValidAt for a more flexible validation of iat, nbf, exp (useful in examples).
    // For strict validation, use ValidAt with a SystemClock.
    $constraints = [
        new IssuedBy('http://example.com'),
        new PermittedFor('http://example.org'),
        // LooseValidAt allows 'iat', 'nbf' to be in the future (within some tolerance)
        // and 'exp' to be in the past (within some tolerance).
        // For production, usually use ValidAt(SystemClock).
        new LooseValidAt(SystemClock::fromSystemTimezone()),
    ];

    // Add a constraint for the specific 'nbf' check if needed, e.g., waiting for 1 minute
    echo "Waiting for 1 minute to satisfy 'nbf' claim before validation...\n";
    sleep(61); // Sleep for 61 seconds to ensure nbf is met
    
    $validator->assert($parsedToken, $constraints);

    echo "Token is valid!\n";

    // Access header and payload claims
    echo "\n--- Token Details ---\n";
    echo "Header: " . json_encode($parsedToken->headers()->all(), JSON_PRETTY_PRINT) . "\n";
    echo "Claims: " . json_encode($parsedToken->claims()->all(), JSON_PRETTY_PRINT) . "\n";
    echo "
";
    echo "Issuer (iss): " . $parsedToken->claims()->get('iss') . "\n";
    echo "User ID (uid): " . $parsedToken->claims()->get('uid') . "\n";
    echo "Roles: " . implode(', ', $parsedToken->claims()->get('roles')) . "\n";

} catch (RequiredConstraintsViolated $e) {
    echo "Token validation failed!\n";
    echo "Violations: ";
    foreach ($e->violations() as $violation) {
        echo "- " . $violation->getMessage() . "\n";
    }
} catch (Throwable $e) {
    echo "An error occurred during parsing or validation: " . $e->getMessage() . "\n";
}

// --- Example of an invalid token (tampered signature) ---

echo "\n--- Example of an invalid token (tampered signature) ---\n";

$tamperedTokenString = $tokenString . 'garbage'; // Simulating a tampered token

try {
    $parsedTamperedToken = $parser->parse($tamperedTokenString);
    $validator = $configParser->validator();
    $validator->assert($parsedTamperedToken, [
        new IssuedBy('http://example.com'),
        new PermittedFor('http://example.org'),
        new LooseValidAt(SystemClock::fromSystemTimezone()),
    ]);
    echo "Tampered token unexpectedly valid! This should not happen.\n";
} catch (RequiredConstraintsViolated $e) {
    echo "Tampered token validation failed as expected!\n";
    foreach ($e->violations() as $violation) {
        echo "- " . $violation->getMessage() . "\n";
    }
} catch (Throwable $e) {
    echo "An error occurred for tampered token: " . $e->getMessage() . "\n";
}

```