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

Jwt Client Bundle Laravel Package

ciricihq/jwt-client-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require ciricihq/jwt-client-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Cirici\JWTClientBundle\CiriciJWTClientBundle::class => ['all' => true],
    ];
    
  2. Configuration Define your JWT server in config/packages/cirici_jwt_client.yaml:

    cirici_jwt_client:
        servers:
            my_jwt_server:
                url: 'https://api.example.com/auth'
                public_key: '-----BEGIN PUBLIC KEY-----...'
                algorithm: 'RS256'
    
  3. First Use Case: Validate a Token

    use Cirici\JWTClientBundle\Client\JWTClient;
    
    $client = new JWTClient('my_jwt_server');
    $isValid = $client->validateToken('Bearer ' . $userToken);
    
  4. First Use Case: Login via JWT

    $client = new JWTClient('my_jwt_server');
    $token = $client->login('username', 'password');
    

Implementation Patterns

Workflow: Token Validation in Controllers

use Symfony\Component\HttpFoundation\Request;
use Cirici\JWTClientBundle\Client\JWTClient;

class AuthController extends AbstractController
{
    public function protectedRoute(Request $request, JWTClient $jwtClient)
    {
        $token = $request->headers->get('Authorization');
        if (!$jwtClient->validateToken($token)) {
            return $this->json(['error' => 'Invalid token'], 401);
        }

        // Proceed with authenticated logic
    }
}

Workflow: External API Integration

use Cirici\JWTClientBundle\Client\JWTClient;

class ExternalService
{
    public function __construct(private JWTClient $jwtClient) {}

    public function fetchProtectedData(string $token): array
    {
        $this->jwtClient->validateToken($token); // Validate before API call
        $client = new \GuzzleHttp\Client();
        $response = $client->get('https://external-api.com/data', [
            'headers' => ['Authorization' => $token],
        ]);
        return json_decode($response->getBody(), true);
    }
}

Integration with Symfony Security

  1. Create a JWT Authenticator:

    use Cirici\JWTClientBundle\Client\JWTClient;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
    use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
    use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
    
    class JWTAuthenticator extends AbstractAuthenticator
    {
        public function __construct(private JWTClient $jwtClient) {}
    
        public function supports(Request $request): ?bool
        {
            return $request->headers->has('Authorization');
        }
    
        public function authenticate(Request $request): Passport
        {
            $token = $request->headers->get('Authorization');
            if (!$this->jwtClient->validateToken($token)) {
                throw new \RuntimeException('Invalid JWT token');
            }
    
            // Extract user ID from token payload (customize based on your JWT structure)
            $userId = $this->jwtClient->getTokenPayload($token)['user_id'];
            return new SelfValidatingPassport(new UserBadge($userId));
        }
    
        public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
        {
            return null; // Let Symfony handle it
        }
    
        public function onAuthenticationFailure(Request $request, \Throwable $exception): ?Response
        {
            return new Response('Authentication Failed', 401);
        }
    }
    
  2. Register in security.yaml:

    security:
        firewalls:
            main:
                pattern: ^/api
                stateless: true
                jwt: ~
    

Token Refresh Logic

use Cirici\JWTClientBundle\Client\JWTClient;

class TokenManager
{
    public function __construct(private JWTClient $jwtClient) {}

    public function refreshTokenIfNeeded(string $token): string
    {
        if ($this->jwtClient->isTokenExpired($token)) {
            $refreshToken = $this->jwtClient->getTokenPayload($token)['refresh_token'] ?? null;
            if ($refreshToken) {
                return $this->jwtClient->refreshToken($refreshToken);
            }
            throw new \RuntimeException('Token expired and no refresh token available');
        }
        return $token;
    }
}

Gotchas and Tips

Common Pitfalls

  1. Public Key Management

    • Ensure the public key is correctly formatted (PEM format) and accessible.
    • If the key changes frequently, implement a caching layer or key rotation logic.
    • Debug Tip: Use openssl rsa -pubin -in key.pem -text -noout to verify key validity.
  2. Token Validation Edge Cases

    • Clock Skew: External JWT servers might have different time settings. Configure leeway in the client:
      cirici_jwt_client:
          servers:
              my_jwt_server:
                  leeway: 60 # Allow 60 seconds of clock skew
      
    • Token Expiry: Always handle TokenExpiredException gracefully. Example:
      try {
          $jwtClient->validateToken($token);
      } catch (\Cirici\JWTClientBundle\Exception\TokenExpiredException $e) {
          return $this->redirectTo('/login?expired=true');
      }
      
  3. Algorithm Mismatch

    • If the server uses a non-standard algorithm (e.g., HS512), ensure it’s supported by the underlying library (firebase/php-jwt).
    • Fix: Update the algorithm in config or extend the bundle to support custom algorithms.
  4. Rate Limiting

    • External JWT servers may throttle requests. Implement retry logic with exponential backoff:
      use Symfony\Component\Panther\Client;
      
      $client = new Client($jwtServerUrl, [
          'timeout' => 10,
          'connect_timeout' => 5,
      ]);
      

Debugging Tips

  1. Enable Verbose Logging Add to config/packages/monolog.yaml:

    handlers:
        main:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
            channels: ["cirici_jwt_client"]
    
  2. Inspect Raw Token Data Use getTokenPayload() to debug token contents:

    $payload = $jwtClient->getTokenPayload('Bearer ' . $token);
    dump($payload); // Inspect claims like 'exp', 'iss', 'sub'
    
  3. Test with Postman/cURL Manually validate tokens using:

    curl -X POST https://api.example.com/auth/validate \
         -H "Authorization: Bearer YOUR_TOKEN" \
         -H "Content-Type: application/json"
    

Extension Points

  1. Custom Claims Validation Extend the JWTClient to add custom claim checks:

    use Cirici\JWTClientBundle\Client\JWTClient;
    use Cirici\JWTClientBundle\Exception\TokenInvalidException;
    
    class CustomJWTClient extends JWTClient
    {
        public function validateToken(string $token): bool
        {
            parent::validateToken($token);
            $payload = $this->getTokenPayload($token);
    
            // Custom logic: e.g., check 'scope' claim
            if (!in_array('admin', $payload['scope'] ?? [])) {
                throw new TokenInvalidException('Insufficient permissions');
            }
    
            return true;
        }
    }
    
  2. Override HTTP Client Replace the default Guzzle client for custom behavior (e.g., proxies, middleware):

    cirici_jwt_client:
        servers:
            my_jwt_server:
                http_client:
                    base_uri: 'https://api.example.com'
                    headers:
                        'X-Custom-Header': 'value'
    
  3. Event Listeners Listen for token validation events (requires extending the bundle or using Symfony events):

    // Example: Log token validation attempts
    $jwtClient->addListener(function (string $token, bool $isValid) {
        \Monolog\Logger::getInstance('security')->info(
            'JWT Validation',
            ['token' => substr($token, 0, 10) . '...', 'valid' => $isValid]
        );
    });
    

Configuration Quirks

  1. Server-Specific Settings Override settings per server:
    cirici_jwt_client:
        servers:
            server_a:
                url
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle